从registerForActivityResult回调,片段销毁时不调用



让我们假设片段有以下ActivityResultLauncher:

class MyFragment : Fragment(R.layout.my_fragment_layout) {
companion object {
private const val EXTRA_ID = "ExtraId"
fun newInstance(id: String) = MyFragment().apply {
arguments = putString(EXTRA_ID, id)
}
}
private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
Timber.i("Callback successful")
}
}
...

由于暂时的体系结构原因,这个片段被包装在一个活动中,它最终将被移动到一个现有的协调器模式中。

class FragmentWrapperActivity : AppCompatActivity() {

private lateinit var fragment: MyFragment
private lateinit var binding: ActivityFragmentWrapperBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityFragmentWrapperBinding.inflate(this)
setContentView(binding.root)
fragment = MyFragment.newInstance("blah")
supportFragmentManager.transact {
replace(R.id.fragment_container, fragment)
}
}
}

我们使用这个启动器来启动一个Activity,期望得到一个结果:

fun launchMe() {
val intent = Intent(requireContext(), MyResultActivity::class.java)
launcher.launch(intent)
}

在具有大量可用内存的普通设备上,这工作得很好。MyResultActivityRESULT_OK结束,回调被调用,我看到日志行。

然而,当内存是一个问题并且调用片段被销毁时,启动器(和它的回调)也会随之被销毁。因此,当MyResultActivity完成时,我的片段的一个新实例被创建,它完全不知道刚刚发生了什么。这可以通过在活动不再有焦点时立即摧毁活动来重现(System -> Developer options -> Don't keep activities)。

我的问题是,如果我的片段依赖于一个启动的活动的状态来处理一些信息,如果这个片段被破坏了,那么这个片段的新实例如何知道在哪里捡起旧片段离开的地方?

你的最小片段是无条件地替换现有的片段与一个全新的片段,每次它被创建,从而导致之前的片段,它已经恢复其状态,被删除。

根据创建片段指南,您总是需要包装您的代码以创建onCreate中的片段,以检查if (savedInstanceState == null):

在前面的例子中,注意片段事务只在savedInstanceState为null时创建。这是为了确保片段只在第一次创建活动时添加一次。当配置发生变化并且重新创建活动时,savedInstanceState不再为空,并且片段不需要第二次添加,因为片段会自动从savedInstanceState恢复。

所以你的代码应该是这样的:
fragment = if (savedInstanceState == null) {
// Create a new Fragment and add it to
// the FragmentManager
MyFragment.newInstance("blah").also { newFragment ->
supportFragmentManager.transact {
replace(R.id.fragment_container, newFragment)
}
}
} else {
// The fragment already exists, so
// get it from the FragmentManager
supportFragmentManager.findFragmentById(R.id.fragment_container) as MyFragment
}

最新更新