安卓现代化开发系列——从生命周期到Lifecycle【扩展包1已更新】-1
https://developer.aliyun.com/article/1398226
3、谷歌眼中的Lifecycle
3.1、ComponentActivity
此类是谷歌官方基于Activity开发的子类,其集成了许多Jetpack库的核心功能,其中就包括了「Lifecycle」库,该类因此也实现了LifecycleOwner
接口,开发者常用的AppcompatActvity
也是该类的子类。
但是细读源码会发现,该类并没有像笔者之前展示的源码那样,直接调用LifecycleRegistry
在特定的Activity
生命周期回调中派发事件,那么该类是如何实现生命周期事件的派发的呢?下面介绍「Lifecycle」库中的另外一个关键类:ReportFragment。
3.1.1、ReportFragment与LifecycleCallbacks
在ComponentActivity
的onCreate()中,有一段ReportFragment.injectIfNeededIn(this)
的代码,这个就是实现了生命周期事件派发的核心类。
接下来让我们走进ReportFragment
的源码,正如前文所述,文章并不会阐述每一行代码的原理,而是抓住主要的脉络,隐藏了和主脉络无关的代码,但是剩余的代码量仍然挺多,读者不必对大量的代码感到恐慌,因为文章会逐一解释:
可见,ReportFragment
做的事非常简单,就是在其生命周期的各个阶段上报生命周期事件,因为Fragment
的生命周期和Activity
在绝大部分是保持一致的(特殊的如onCreate()
除外,不过也有onActivityCreated()
、onActivityPostCreated()
等可以感知Activity
生命周期的函数),谷歌的开发人员于是就利用ReportFragment
作为监听Activity
生命周期的工具,你可以看到这个Fragment是没有UI的,这也间接证明了它的任务并不是展示一个UI而仅仅是为了监听生命周期。
让我们回到injectIfNeedIn() ,可以清楚的看到这里做了一个版本判断,如果大于api版本大于29,则使用LifecycleCallbacks
做一个注册的逻辑,这是怎么回事呢?
在我提到ReportFragment
是作为一个生命周期监听者而不是一个展示UI的模块的时候,你也许就已经隐隐约约闻到一种非常奇怪的味道。由于安卓源码设计的缺陷(只对外提供了回调方法而没有提供回调监听注册),开发者对待这一问题必须考虑向下兼容,因此他们选择了源码中已经存在的、可以监听Activity
的生命周期的Fragment
,但是在api 29之后,Activity原生自带了生命周期的回调监听注册,因此一旦检测到api大于或者等于29,ReportFragment
的作用就形同虚设了,因为广播生命周期的事件的任务已经转移给Activity
自带的生命周期回调来实现了。
你也许还会担心,现在有ReportFragment
和Activity
自带的生命周期回调两种方式了,会不会导致一个事件被广播两次呢?其实不用担心,广播的时候已经做了排除了,只有api小于29的情况下,ReportFragment
才会生效。
3.2、Fragment
Fragment
本身的生命周期和Activity
没有很大的差异,依然是内置LifecycleRegistry
然后在合适的生命周期回调中广播生命周期事件的一套,但是值得注意的是:
当
Fragment
被FragmentManager
管理时,例如执行replace()
事务中,逻辑上当前的Fragment
只是被另外一个同类所替换了,它并没有真的被销毁(因为待会还有重新回来的机会),因此该Fragment
并不会执行onDestroy()
,然而由于内存上的考量,不可见的Fragment
的View
理应被回收,因此View
会被销毁。换句话说,
Fragment
不可见之后,它的状态会保存起来,但是其View
会被销毁,待会再次可见的时候,会根据其状态再一次执行onCreateView() 。
上述机制导致了一个问题:Fragment
的生命周期和其对应的View
的生命周期在实质上是不对等的,然而实际开发中感知生命周期大多数是为了与UI进行互动,这也导致了开发者单纯监听Fragment
的生命周期已经不能够满足开发上的需求了。
下面这张来源于谷歌官方开发者文档的图片很好的诠释了Fragment
和它的View
的生命周期关系:
假如一个Fragment
正在栈顶,他会处于Resumed的阶段,但是被replace之后(或者说是进入了回退栈),它会进入Created阶段,此刻View
被销毁,View
会进入Destroyed阶段,但是Fragment
重回栈顶的时候,Fragment
会从Created再次回归到Resume,而View
会从Destroyed重回Resumed状态。
换句话说,在Fragment
的生命周期中,它的View可能会反复的从Destroyed到Resumed之间移动(即不断地销毁与创建)
谷歌为了缓解这个问题,给Fragment
的View
单独添加了一套生命周期,我们可以通过代码看到端倪:
可以看到,在Fragment
执行performCreateView()
的时候,会初始化View
的Lifecycle,两者的生命周期事件是单独通知的。
- 如果开发者想访问
Fragment
的生命周期,在Fragment
中访问lifecycleOwner
即可。 - 如果开发者想访问
Fragment
的View
的生命周期,在Fragment
中访问viewLifecycleOwner
即可。
3.3、ViewTreeLifecycleOwner
在上述的代码中,能够直接访问Activity
、Fragment
的Lifecycle的只能是它们的类中,而很多需要访问生命周期的地方往往是一些View
中,例如要在View
中监听其父组件生命周期,然而View
的父控件有非常多,包括了Activity
、Fragment
甚至是Dialog
乃至更多,要想获取父组件的生命周期,只能做类型判断+类型强转的工作,这样就极大的限制了View
的使用范围:
为了缓解,谷歌的开发人员提出了一种叫ViewTreeLifecycleOwner
的设计,其实这个东西并没有什么神秘的,让我们直接看看源码:
通篇只有两个View
的扩展函数,第一个函数的意义是给对应的View
绑上一个LifecycleOwner
,第二个函数的意义是不断往上查找父控件,直到查出之前绑定的LifecycleOwner
。
这段源码的作用挺简单的,也就是说只要给某个顶层的控件提前绑好了LifecycleOwner
,那么他下辖的所有子View
都可以通过往上查找的方式来找到LifecycleOwner
,不得不说谷歌的开发人员真的是太厉害了,在简陋的基础下做出了非常强大的功能。
那么下面的问题是:LifecycleOwner
的绑定发生在哪里呢?
3.3.1、Activity中的绑定
Activity的直接子类ComponentActivity
、AppcompatActivity
均自动完成了绑定的工作,我们以ComponentActivity
为例看看相关的绑定代码:
可见在ComponentActivity
的setContentView
被执行时,会将Activity
的ViewLifecycleOwner
绑定其所在的Window
的DecorView
中,我们都知道Activity
下面的所有View
都是DecorView
的子View,因此它们都可以直接通过谷歌开发人员提供的扩展函数直接访问到最顶层的Activity
的Lifecycle
。
#3.3.2、Fragment中的绑定
和Activity
类似,Fragment
也采用了几乎一致的绑定方式,只不过是将Lifecycle
绑定在了Fragment
的View
之上:
3.3.3、Dialog中的绑定
默认的Dialog
和Activity
是不支持ViewTreeLifecycleOwner
的,因此谷歌的开发人员重新继承实现了一个新的Dialog子类:ComponentDialog
,其中的绑定大同小异,简单看下源码即可了解:
看来和Activity
一样,把LifecycleOwner
绑定在了DecorView
中。
3.3.4、意义与总结
那么谷歌的开发人员费尽心思的为以上的组件绑定ViewTreeLifecycleOwner
有何用意呢?意义可大了,由于消除了组件之间的差异(均是通过View
往上查找父控件直到找到LifecycleOwner
的模式),我们不用在乎当前的View
是在哪个控件中,都是统一通过findViewTreeLifecycleOwner()
来获取最顶层控件的生命周期。
例如下面的自定义View的代码,无论在上述哪个控件中都可以用:
可见,开发者只需要关注生命周期本身,不再需要担心不同组件之间的差异了。
4、结语
安卓原生的生命周期设计只能说是毛坯房都算不上的水平,然而通过「Lifecycle」库的加持之后,开发者可以轻松访问组件的生命周期,让开发业务更加的合理与安全。
作为开发者的你,应该逐渐将重写生命周期函数的方式逐渐过渡到「Lifecycle」的开发方式中来,在一些工具类亦或者其他业务类中,你也可以使用「Lifecycle」辅助强化与生命周期相关的业务。
如果文章帮助到你,请为笔者点一个👍🏻支持一下,你的鼓励是我前进的动力!
安卓现代化开发系列——从生命周期到Lifecycle【扩展包1已更新】-3
https://developer.aliyun.com/article/1398235?spm=a2c6h.13148508.setting.14.e4774f0eb3rwuq