本文出自​​【赵彦军的博客】​​

文章目录

  • ​​ViewTreeLifecycleOwner是什么?​​
  • ​​实现原理?​​
  • ​​ComponentActivity​​
  • ​​Fragment​​
  • ​​DialogFragment​​
  • ​​ComponentDialog​​
  • ​​Fragment 作为 LifecycleOwner 遇到的坑​​
  • ​​onCreate​​
  • ​​onViewCreated​​
  • ​​getViewLifecycleOwnerLiveData​​
  • ​​lifecycleScope​​
  • ​​总结​​

ViewTreeLifecycleOwner是什么?

​ViewTreeLifecycleOwner​​​ 是​​Lifecycle KTX​​​中提供的​​View​​​的一个扩展方法,可以快速地获取一个最近的​​Fragment​​​或者​​Activity​​​的​​LifecycleOwner​​。

view.findViewTreeLifecycleOwner()

Android 使用ViewTreeLifecycleOwner获取Lifecycle_android

实现原理?

ComponentActivity

通过 ​​ViewTreeLifecycleOwner.set​​​ 将当前 ​​lifecycle​​​ 设置到​​decorView ​

Android 使用ViewTreeLifecycleOwner获取Lifecycle_zhaoyanjun_02

Fragment

通过 ​​ViewTreeLifecycleOwner.set​​​ 将当前 ​​lifecycle​​​ 设置到根​​view ​

Android 使用ViewTreeLifecycleOwner获取Lifecycle_Lifecycler_03

DialogFragment

通过 ​​ViewTreeLifecycleOwner.set​​​ 将当前 ​​lifecycle​​​ 设置到​​decorView ​

Android 使用ViewTreeLifecycleOwner获取Lifecycle_赵彦军_04

ComponentDialog

通过 ​​ViewTreeLifecycleOwner.set​​​ 将当前 ​​lifecycle​​​ 设置到​​decorView ​

Android 使用ViewTreeLifecycleOwner获取Lifecycle_LifeCycleOwner_05

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")
}
}
}

这就行了? 等等,会报错

Android 使用ViewTreeLifecycleOwner获取Lifecycle_zhaoyanjun_06


意思是,这里的 ​​LifecyclerOwner​​​ 要使用 ​​viewLifecyclerOwner​​ , 代码如下:

Android 使用ViewTreeLifecycleOwner获取Lifecycle_android_07


为什么会报错?

​LiveData​​​ 之所以能够防止泄露,是当 ​​LifecycleOwner​​​ 生命周期走到 ​​DESTROYED​​​ 的时候会 ​​remove​​​ 调其关联的 ​​Observer​​。

Android 使用ViewTreeLifecycleOwner获取Lifecycle_赵彦军_08


是由于 ​​Fragment​​​ 的 ​​Lifecycle​​​ 与 ​​Fragment#mView​​​ 的 ​​Lifecycle​​​ 不一致导致我们订阅 ​​LiveData ​​​的时机和所使用的 ​​LivecycleOwner​​ 不匹配

Android 使用ViewTreeLifecycleOwner获取Lifecycle_LifeCycleOwner_09

明白了问题原因,解决思路也就清楚了:必须要保证订阅的时机和所使用的 ​​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​​。

Android 使用ViewTreeLifecycleOwner获取Lifecycle_android_10

总结

随着 ​​MVVM​​​ 的普及,我们可能需要在​​View ​​​ 内部基于​​lifecycle​​​ 进行​​livedata​​​ 订阅等工作,当​​View​​​嵌套比较深时,使用​​ViewTreeLifecycleOwner​​​扩展方法可以避免​​lifecycle​​的层层传递,简化代码.