本文出自【赵彦军的博客】
文章目录
- ViewTreeLifecycleOwner是什么?
- 实现原理?
- ComponentActivity
- Fragment
- DialogFragment
- ComponentDialog
- Fragment 作为 LifecycleOwner 遇到的坑
- onCreate
- onViewCreated
- getViewLifecycleOwnerLiveData
- lifecycleScope
- 总结
ViewTreeLifecycleOwner是什么?
ViewTreeLifecycleOwner
是Lifecycle KTX
中提供的View
的一个扩展方法,可以快速地获取一个最近的Fragment
或者Activity
的LifecycleOwner
。
view.findViewTreeLifecycleOwner()
实现原理?
ComponentActivity
通过 ViewTreeLifecycleOwner.set
将当前 lifecycle
设置到decorView
Fragment
通过 ViewTreeLifecycleOwner.set
将当前 lifecycle
设置到根view
DialogFragment
通过 ViewTreeLifecycleOwner.set
将当前 lifecycle
设置到decorView
ComponentDialog
通过 ViewTreeLifecycleOwner.set
将当前 lifecycle
设置到decorView
Fragment 作为 LifecycleOwner 遇到的坑
onCreate
在 Fragment
的 onCreate
用 this
做 LifecycleOwner
没有问题。
class MyFragment : Fragment() {
private val viewModel by activityViewModels<MyViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.some.observe(this) { }
}
}
因为在 Fragment
Destory
会自动移除监听。
onViewCreated
那么我们在 onViewCreated
还能使用上面的监听代码吗?
试试看
class MyFragment : Fragment() {
private val viewModel by activityViewModels<MyViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.some.observe(this) {
Log.d("yu--", "some $it")
}
}
}
这就行了? 等等,会报错
意思是,这里的 LifecyclerOwner
要使用 viewLifecyclerOwner
, 代码如下:
为什么会报错?
LiveData
之所以能够防止泄露,是当 LifecycleOwner
生命周期走到 DESTROYED
的时候会 remove
调其关联的 Observer
。
是由于 Fragment
的 Lifecycle
与 Fragment#mView
的 Lifecycle
不一致导致我们订阅 LiveData
的时机和所使用的 LivecycleOwner
不匹配
明白了问题原因,解决思路也就清楚了:必须要保证订阅的时机和所使用的 LifecycleOwner
相匹配,即要么调整订阅时机,要么修改LifecycleOwner
。
getViewLifecycleOwnerLiveData
顺道提一下,与 getViewLifecycleOwner
同时新增的还有 getViewLifecycleOwnerLiveData
。从前面贴的源码中对 mViewLifecycleOwnerLiveData
的使用,应该可以猜出它的作用:它是前文讨论的思路1的实现方案,即使在 onCreate
中订阅,由于在 onCreateView
中对 LiveData
进行了重新设置,所以重建后的 View
也可以更新数据。
// Then inform any Observers of the new LifecycleOwner
mViewLifecycleOwnerLiveData.setValue(mViewLifecycleOwner);
需要特别注意的是,根据 MVVM
最佳实践,我们希望由 ViewModel
而不是 Fragment
持有 LiveData
,所以不再推荐使用 getViewLifecycleOwnerLiveData
。
lifecycleScope
前面都是以 LiveData
为例介绍对 ViewLifecycleOwner
的使用, 如今大家也越来越多的开始使用协程的 StateFlow
, 同样要注意不要错用 LifecycleOwner
。
订阅 StateFlow
需要 CoroutineScope
, AndroidX
提供了基于 LifecycleOwner
的扩展方法。
val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
get() = lifecycle.coroutineScope
当我们在 Fragment
中获取 lifecycleScope
时,切记要使用 ViewLifecycleOwner
。
总结
随着 MVVM
的普及,我们可能需要在View
内部基于lifecycle
进行livedata
订阅等工作,当View
嵌套比较深时,使用ViewTreeLifecycleOwner
扩展方法可以避免lifecycle
的层层传递,简化代码.