如何正确调用上下文以启动 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
的一部分,而Activity
是Context
的间接子类。
您可能尝试了以下方法并且成功了:
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
附加到Activity
,Fragment
的context
属性是Activity
的上下文,否则它是null
。因此,如果不是null
,您可以使用它来启动Activity
。
但您甚至可以使用Button
的context
属性,因为它也与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