在 android 的 onResume 之后使用 ActivityResultRegistry 注册合同有多安全?
How safe is registering contracts with ActivityResultRegistry after onResume in android?
以下代码给我错误,因为在 onResume 之后发生注册:
class TempActivity: AppCompatActivity(){
private lateinit var binding: ActivityTempBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTempBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tempBtn.setOnClickListener {
val a = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
//SomeCode
}
a.launch(
//SomeIntent
)
}
}
但是,如果我使用 activityResultRegistry,我不会收到任何错误。密码是
class TempActivity: AppCompatActivity(){
private lateinit var binding: ActivityTempBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTempBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tempBtn.setOnClickListener {
val a = activityResultRegistry.register("key", ActivityResultContracts.StartActivityForResult()){
// SomeCode
}
a.launch(
//Some Intent
)
}
}
后面的代码运行没有任何问题,并启动了相应的意图。我只想知道后一个有多安全,是否有任何我应该注意的不良行为?
它给你一个错误,因为你在 Activity 进入其生命周期后 有条件地 注册合同。
guide 说:
You must always call registerForActivityResult()
in the same order for each creation of your fragment or activity to ensure that the inflight results are delivered to the correct callback.
很明显,如果你在创建Activity之后注册一些东西,并且只有在满足条件(本例中是点击事件)时才会发生,无法保证注册的顺序。
更好的解决方案是在创建 Activity 之前注册合约,并在需要时调用 launch()
。该指南再次表示它是完全安全的:
registerForActivityResult()
is safe to call before your fragment or activity is created, allowing it to be used directly when declaring member variables for the returned ActivityResultLauncher instances.
所以在你的情况下,Activity 看起来像这样:
class TempActivity: AppCompatActivity() {
private lateinit var binding: ActivityTempBinding
// registering the contract here
private val a = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
//SomeCode
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTempBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tempBtn.setOnClickListener {
// launching the registered contract
a.launch(
//SomeIntent
)
}
}
}
进一步说明:
registerForActivityResult()
是一种方便的方法,它使用自动创建的密钥在内部调用注册表的 register
方法。密钥派生自内部 AtomicInteger
,每次调用 registerForActivityResult()
时都会检索并递增该密钥。由于此键用于查找将处理结果的回调,因此对 registerForActivityResult
的每次调用必须以相同的顺序进行,否则可能会发生您按 A (key=0), B (key=1) 然后你称它为 B (key=0), A (key=1),或者甚至不调用其中一个合约的 register 方法(这正是您在 OnClickListener
中注册时发生的情况)。
在您的特定情况下,如果在您等待启动合约到 return 时重新创建 Activity(例如,发生配置更改或系统简单地终止应用程序),则callback 将从注册表中删除(尽管密钥保留在那里),这意味着它不会与结果一起调用。
因此,总结一下整个事情:您可以(应该)安全地将任何合约注册为您的Activity或[=20=中的成员字段],你永远不应该注册合同 on-the-fly(a.k.a。有条件地)。注册合约没有什么特别的,真正的交易发生在你启动它时。
以下代码给我错误,因为在 onResume 之后发生注册:
class TempActivity: AppCompatActivity(){
private lateinit var binding: ActivityTempBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTempBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tempBtn.setOnClickListener {
val a = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
//SomeCode
}
a.launch(
//SomeIntent
)
}
}
但是,如果我使用 activityResultRegistry,我不会收到任何错误。密码是
class TempActivity: AppCompatActivity(){
private lateinit var binding: ActivityTempBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTempBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tempBtn.setOnClickListener {
val a = activityResultRegistry.register("key", ActivityResultContracts.StartActivityForResult()){
// SomeCode
}
a.launch(
//Some Intent
)
}
}
后面的代码运行没有任何问题,并启动了相应的意图。我只想知道后一个有多安全,是否有任何我应该注意的不良行为?
它给你一个错误,因为你在 Activity 进入其生命周期后 有条件地 注册合同。
guide 说:
You must always call
registerForActivityResult()
in the same order for each creation of your fragment or activity to ensure that the inflight results are delivered to the correct callback.
很明显,如果你在创建Activity之后注册一些东西,并且只有在满足条件(本例中是点击事件)时才会发生,无法保证注册的顺序。
更好的解决方案是在创建 Activity 之前注册合约,并在需要时调用 launch()
。该指南再次表示它是完全安全的:
registerForActivityResult()
is safe to call before your fragment or activity is created, allowing it to be used directly when declaring member variables for the returned ActivityResultLauncher instances.
所以在你的情况下,Activity 看起来像这样:
class TempActivity: AppCompatActivity() {
private lateinit var binding: ActivityTempBinding
// registering the contract here
private val a = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
//SomeCode
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTempBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tempBtn.setOnClickListener {
// launching the registered contract
a.launch(
//SomeIntent
)
}
}
}
进一步说明:
registerForActivityResult()
是一种方便的方法,它使用自动创建的密钥在内部调用注册表的 register
方法。密钥派生自内部 AtomicInteger
,每次调用 registerForActivityResult()
时都会检索并递增该密钥。由于此键用于查找将处理结果的回调,因此对 registerForActivityResult
的每次调用必须以相同的顺序进行,否则可能会发生您按 A (key=0), B (key=1) 然后你称它为 B (key=0), A (key=1),或者甚至不调用其中一个合约的 register 方法(这正是您在 OnClickListener
中注册时发生的情况)。
在您的特定情况下,如果在您等待启动合约到 return 时重新创建 Activity(例如,发生配置更改或系统简单地终止应用程序),则callback 将从注册表中删除(尽管密钥保留在那里),这意味着它不会与结果一起调用。
因此,总结一下整个事情:您可以(应该)安全地将任何合约注册为您的Activity或[=20=中的成员字段],你永远不应该注册合同 on-the-fly(a.k.a。有条件地)。注册合约没有什么特别的,真正的交易发生在你启动它时。