ViewModel 没有在导航中被清除,并且视图模型中的实时数据保持活动状态

Ron*_*upu 6 navigation android android-fragments android-livedata android-viewmodel

因此,我使用导航实现了具有多个片段模式的单个活动。我为非 ui 操作的每个片段使用了视图模型。

问题是当您使用 导航时findNavController().navigate(),片段实际上并未被销毁。只有onDestroyView被调用。因此,片段的 onDestroy 永远不会被调用,随后视图模型也不会被清除,因此 LiveData 观察者也保持活动状态,当我回到片段时,观察者再次被创建,因此实时数据被观察到两次。一次使用它保存的旧数据,第二次使用来自某些操作的新数据。

例如,我有片段A和片段B

A显示一个列表,B您可以添加将显示在列表中的内容。也许从片段B 中的api 获取新数据以显示在A 中

因此,当我从片段B返回到A 时,观察者首先使用旧数据调用两次,然后使用更新数据调用第二次。最后,列表显示了正确的数据,但我不希望出现两个观察者。

我已经关注了这篇文章 https://medium.com/@BladeCoder/architecture-components-pitfalls-part-1-9300dd969808

并尝试使用viewLifeCycleOwner代替,this但这无济于事,问题仍然存在。

我还尝试在观察之前删除观察者:

vm.ld.removeObservers(this)
vm.ld.observe(viewLifeCyclerOwner, observer)
Run Code Online (Sandbox Code Playgroud)

问题仍然存在。

(我也尝试删除观察者onDestroyView,但问题仍然存在。)

唯一的周围,我发现工作是手动调用视图模型onClearedonDestroyView,并清除livedata。

在片段 onDestroyView

vm.clear()
Run Code Online (Sandbox Code Playgroud)

在视图模型中

fun clear() = onCleared()

override fun onCleared() {
  //do stuff
}
Run Code Online (Sandbox Code Playgroud)

现在,这解决了我的问题。但我觉得这不是一个可靠的解决方案,可以有更好的方法来做到这一点。如果有人能对此有所了解,我会很高兴。谢谢。

rmi*_*lle 6

我浪费了几天时间来解决类似的问题。仔细检查您的虚拟机是如何初始化的:

val myVm: MyViewModel by activityViewModels()
Run Code Online (Sandbox Code Playgroud)

val myVm: MyViewModel by viewModels()
Run Code Online (Sandbox Code Playgroud)

如果您使用by activityViewModels()委托,您将指示 Android 将 VM 的生命周期与主机活动而不是当前 Fragment 联系起来。因此,即使片段被销毁,您的虚拟机也不会被清除。我经过惨痛的教训才学到这个。切换回by viewModels()委托会将 VM 的范围限制在 Fragment 的生命周期内。当片段被销毁时,如果它是唯一的观察者,则VM将清除。

观察时我对目标与目标this完全混淆了。viewLifecycleOwner显然,目标的选择仅与您是否打算手动控制 DialogFragment 的对话框呈现有关。又一个令人困惑的宝石。

在您的情况下,如果您在片段之间切换并且onDestroy没有被调用,也可能是因为片段被保留。例如,ViewPager2has offscreenPageLimit,它指示 Android 在您切换页面时将隐藏的片段保留在内存中,这进一步加剧了必须了解所有内容才能使用 SDK 的混乱情况。


kov*_*777 0

您可以viewModelStore.clear()在片段中使用,然后onCleared()在 ViewModel 中覆盖以处理您需要的内容