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

How do I call the context correctly to start an Activity

自从我遇到这种类型的崩溃:

Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

一开始我开始想知道上下文的正确用法Activity-Intent。

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

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@ActivityName。 因此,我想请您礼貌地向我解释,当从 Activity、片段或函数或使用 CoroutineScope[=14] 开始 Activity 时,如何知道哪个是正确的上下文=]

谢谢

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

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

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 上下文继承的 "cousin"(请参阅 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。如果你想要另一个,"outer this",你必须明确地说出是哪个。在 Kotlin 中,您可以通过添加 @ActivityName 来实现。

我想 Activity 中的协程代码也是如此(尽管我必须承认我还不是协程专家):只要 Activity "this" 隐藏在后面一些本地 "this",你需要注释。

回到熟悉的地方:Fragmentcontext 属性 是 Activity 的上下文,如果 Fragment 附加到 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)
        }
    }

如果使用科特林

    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)    
}