喷气背包生命周期:片段的视图生命周期永远不会达到创建状态,永远不会销毁



>问题

我最近注意到一种情况,在Android应用程序中,触发了以下异常:

java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles

当为视图模型的实时数据注册一些观察者时,在片段的onViewCreated回调(例如片段 A)中,就会发生这种情况:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
myViewModel.myLiveData.observe(viewLifecycleOwner, Observer(::onValueChanged))
...
}

这让我发现这发生在一种特定情况下,当在活动的onCreate中收到意图并决定导航到另一个片段(例如片段 B)时。

override fun onCreate(savedInstanceState: Bundle?) {
if ("myAction" == intent?.action) {
if (R.id.fragmentA == navController.currentDestination?.id) {
navController.navigate(FragmentADirections.actionFragmentAToFragmentB())
}
}
}

如果用户从该片段 B 导航回片段 A,则会抛出该IllegalArgumentException

调查

在记录生命周期方面发生的事情后,我意识到片段 A 的生命周期状态viewLifecycleOwner当片段为 LiveData 注册观察者时INITIALIZED。 这与文档建议的内容相符:

。然后,getViewLifecycle OwnerLiveData() 使用与片段视图对应的新初始化的 Lifecycle Owner 进行更新。此时也会调用 onViewCreated() 生命周期回调。

这是设置视图初始状态的合适位置,开始观察 LiveData 实例,这些实例的回调更新了片段的视图......

但是,当活动从其onCreate回调控制导航时,片段视图的生命周期永远不会达到STARTED状态,也不会在显示片段 B 时向下DESTROYED。因此,从片段 B 返回到片段 A,以前的生命周期所有者观察 LiveData,片段的新生命周期所有者也尝试观察它,引发异常。

[编辑] 我一直试图找出可能触发此异常的更改。我使用androidx.lifecycle:lifecycle-viewmodel-ktx的版本2.5.12.6.0运行代码,我发现异常是由版本2.6.0(和2.6.1)触发的,而不是版本2.5.1触发的。我还在片段回调中添加了日志,发现两个版本都调用了onViewCreated

onCreateView: Fragment view is INITIALIZED
onViewCreated: Fragment view is INITIALIZED
onDestroyView: Fragment view is INITIALIZED

[/编辑]

当用户"手动"导航到另一个片段并且片段视图的生命周期从INITIALIZEDCREATED向下到DESTROYED时,我还记录

了。

问题

出现了几个问题:生命周期能否从INITIALIZED直接变为DESTROYED状态?还是我这边没有向下走的错误?

如果不是,正确的做法是什么?一旦生命周期达到CREATED状态,是否应该稍后观察 LiveData?

还是活动不应该这么早导航到另一个片段?它是否应该等待片段显示视图后再导航(显然它不适合用户体验)?

我不认为这是一个明确的答案,但我看到了解决问题的两种方法。

一种是将喷气背包生命周期库降级,特别是androidx.lifecycle:lifecycle-viewmodel-ktx,以2.5.1

另一种是从活动的onStart回调导航到其他片段。

相关内容

  • 没有找到相关文章

最新更新