如何正确调用上下文以启动 Activity

Posted

技术标签:

【中文标题】如何正确调用上下文以启动 Activity【英文标题】:How do I call the context correctly to start an Activity 【发布时间】:2020-05-13 03:11:57 【问题描述】:

自从我经历过这种类型的崩溃:

从 Activity 上下文之外调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是你想要的吗?

我开始想知道如何正确使用 startActivity-Intent 的上下文。

这是我的 Kotlin 代码(活动 -> 活动):

btn_scan.setOnClickListener 
            val mIntent = Intent(applicationContext, Scanner::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
            applicationContext.startActivity(mIntent)    

        

我可以用“this”解决这个问题:

btn_scan.setOnClickListener 
            val mIntent = Intent(this, Scanner::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
            this.startActivity(mIntent)    

        

但现在我对 this 的正确用法有点不安全,因为从内部函数访问它例如需要 this@ActivityName。 所以我想请你礼貌地解释一下,当从 Activity、从 Fragment 或从函数或使用 CoroutineScope 启动 Activity 时,如何知道哪个是正确的上下文

谢谢

【问题讨论】:

这能回答你的问题吗? What's the difference between the various methods to get a Context? 部分地,this 和 this@Activity 仍然不是 100% 清楚 【参考方案1】:

不确定我是否能回答你所有的问题,但这是我的两分钱:

当您的应用崩溃时,您的代码如下所示:

btn_scan.setOnClickListener 
            val mIntent = Intent(applicationContext, Scanner::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
            applicationContext.startActivity(mIntent)    

错误消息说从Activity 上下文之外启动Activity 时应该使用FLAG_ACTIVITY_NEW_TASK。您使用了Application 上下文,它类似于Activity 上下文继承方面的“表亲”(有关子类及其关系,请参阅ContextWrapper),因此检查了Intent 标志并且缺少所需的标志。

但是如果你明确设置它为什么会丢失?

mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

这是因为您在此之后立即为 mIntent.flags 分配了另一个值:

mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP

如果你想同时拥有这两个标志,你必须添加它们:

mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + Intent.FLAG_ACTIVITY_CLEAR_TOP

现在应用不再崩溃了。

但是Application 上下文在这里甚至是必要的吗?毕竟,您的代码是Activity 的一部分,而ActivityContext 的间接子类。

您可能尝试了以下方法并且成功了:

btn_scan.setOnClickListener // Note: your IDE tells you "it: View!"
            val mIntent = Intent(applicationContext, Scanner::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
            this.startActivity(mIntent)    

因为在OnClickListener lambda 内部,View 被“it”引用,没有歧义:“this”指的是Activity,没有崩溃。 (当然现在你可以跳过Intent.FLAG_ACTIVITY_NEW_TASK

当你有这样的东西时,事情看起来会有所不同:

  with(btn_scan) // this: Button!
        setOnClickListener // it: View!
            val mIntent = Intent(applicationContext, Scanner::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + Intent.FLAG_ACTIVITY_CLEAR_TOP
            this.startActivity(mIntent)
        
    

现在您的 IDE 将不接受 this.startActivity(mIntent)。这是因为这里的“this”指的是Button。如果你想要另一个,“在这个之外”,你必须明确地说出是哪一个。在 Kotlin 中,您可以通过添加 @ActivityName 来实现。

我想Activity 中的协程代码也是如此(尽管我必须承认我还不是协程专家):每当Activity“this”隐藏在某个本地“this”后面时,您需要注释。

回到熟悉的基础:如果Fragment 附加到ActivityFragmentcontext 属性是Activity 的上下文,否则它是null。因此,如果不是null,您可以使用它来启动Activity

但您甚至可以使用Buttoncontext 属性,因为它也与Activity 上下文相同:

with(btn_scan) // this: Button!
        setOnClickListener
            val mIntent = Intent(applicationContext, Scanner::class.java)
            mIntent.flags =  Intent.FLAG_ACTIVITY_CLEAR_TOP
            this.context.startActivity(mIntent)
        
    

【讨论】:

您完美地解释了标志问题。一个问题。所以对于 CLEAR_TOP,我已经在访问新活动的 applicationContext,这就是它导致崩溃的原因,对吧? 嗯,这不仅仅是 2 美分,这就是我想要的!现在,我用 val mIntent= Intent(this,Scanner::class.java) ... 和 this.startActivity(mIntent) 解决了它,它似乎无处不在。 @Los Kayos - 感谢您让我知道 :) 关于“对于 CLEAR_TOP 我正在访问新活动的 applicationContext” - AFAIK 任何应用程序组件只能访问其自己的应用程序上下文(直接作​​为属性或间接取决于组件的类型) ' 最好使用 "Intent.FLAG_... + Intent.FLAG_" 或 "Intent.FLAG 或 Intent.FLAG_.."' - 在这种情况下,我更喜欢 "+",它是更接近 "and" ,所以它类似于我用英语所说的 关于“this”的更多信息:如果 OnClickListener 是 Activity 代码的一部分,我的评论是有效的,在 Fragment 中,当需要 Context 时,您必须编写 this.context【参考方案2】:

如果使用 kotlin

    btn_scan.setOnClickListener 
            val mIntent = Intent(this, Scanner::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
            this.startActivity(mIntent)    

【讨论】:

以上是关于如何正确调用上下文以启动 Activity的主要内容,如果未能解决你的问题,请参考以下文章

无法从 BottomSheetDialog 启动Activity

在 Activity 上下文之外调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK

从 Activity 上下文之外调用 startActivity()

从非活动类中获取上下文

何时调用活动上下文或应用程序上下文?

Android:调用 Activity 时应用程序关闭。意图,上下文,字符串[重复]