0.前言
文本先讨论Lifecycle出现之前开发中的一些问题,通过对比说明Lifecycle的好处。之后着重讲述Lifecycle中状态与事件的关系,简单说了一下LiveData依赖Lifecycle实现的特性,最后分析了Lifecycle的工作流程。
1.Lifecycle之前的世界
百度翻译: Lifecycle—生命周期
正如它的名字,Lifecycle是Google为了帮助开发者更好更方便的利用Activity或Fragment生命周期开发的的组件。
在没有Lifecycle之前,处理Activity或Fragment生命周期是一个头疼的问题。
生命周期的情况多比较复杂,Activity与Fragment它们两个之间有千丝万缕的联系但是又不完全一致,所以在开发时可能会考虑很多细节
Lifecycle是在开发者与Activity和fragment之间建立的一个抽象层,Lifecycle将Activity和fragment的生命周期API简化抽象。
使得开发者在开发各种组件时如果有用到生命周期,不需要去和Activity或Fragment打交道 。
不需要开发者去扣细节,扣顺序。开发人员只需要关注Lifecycle即可。
简而言之,Lifecycle用来感知Activity和Fragment的生命周期状态变化。在Android开发中定义的大多数组件都需要感知组件的生命周期,比如:轮播图,播放器等等。
在没有Lifecycle之前这一类组件会暴露出对应的生命周期方法,比如:onResume,onPause。在Activity或Fragment对应的生命周期中调用。
乍一看没有问题,但在真实情况下,可能会有很多组件需要响应Activity生命周期,会导致Activity的生命周期中存在大量业务代码,难以维护。
如下代码:
class MainActivity : AppCompatActivity() {
private lateinit var banner: Banner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
banner = Banner(this);
}
override fun onResume() {
super.onResume()
banner.start()
}
override fun onStop() {
super.onStop()
banner.stop()
}
}
class Banner(private val context: Context) {
fun start() {
}
fun stop() {
}
}
2.Lifecycle之后的世界
自定义的组件接入Lifecycle之后就会拥有感知Activity生命周期的能力,则可以将控制生命周期的代码收归与组件内部,自动调整状态,无需Activity参与。如下代码:
- MainActivity 的代码很简单,初始化Banner,Banner与lifecycle关联
- Banner所有的逻辑都在内部实现,外部调用无需关注
class MainActivity : AppCompatActivity() {
private lateinit var banner: Banner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
banner = Banner()
lifecycle.addObserver(banner)
}
}
class MainFragment : Fragment() {
private lateinit var banner: Banner
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
banner = Banner()
lifecycle.addObserver(banner)
}
}
internal class Banner() : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
start()
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
stop()
}
private fun start() {
}
private fun stop() {
}
}
通过对比可以总结使用Lifecycle好处:
- lifecycle的使用无论是在Activity 或 Fragment中都是一致的,没有任何改变,无需关注两者的生命周期的异同点。
- 能够让三方组件在其内部随时拿到Activity的生命周期,执行自身逻辑,减少外部调用,降低代码复杂度
- 因为所有代码都在三方组件内部,调试更方便,符合职责单一原则
3.Lifecycle的事件与状态
如图所示:
- 整个组件的结构还是非常简单的
- LifecycleObserver 观察 Lifecycle 从而得到 LifecycleOwner 的生命周期状态 和 生命周期切换产生的事件
- Lifecycle基于LifecycleObserver 的生命周期是从LifecycleOwner得到的
- LifecycleObserver 与 LifecycleOwner 没有直接关系
上面提到**状态(States)与事件(Events)**是Lifecycle核心概念
Lifecycle把Activity和fragment的生命周期抽象成五个状态:已初始化,已销毁,已创建,已开始,已恢复。对于开发者来说,Activity 或 Fragment只会在这五种状态来回切换,切换的过程中会发出事件。
如下图:
- initialized 切换到 created 状态 发送事件 onCreate
- created 切换到 started 状态 发送事件 onStart
- started 切换到 resumed 状态 发送事件 onResume
- resumed 切换到 started 状态 发送事件 onPause
- started 切换到 created 状态 发送事件 onStop
- created 切换到 destroyed 状态 发送事件 onDestroy
框架内定义为枚举类
状态:DESTROYED
INITIALIZED
CREATED
STARTED
RESUMED
事件:ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
Lifecycle将Activity,Fragment 生命周期的切换抽象为 事件与状态。
事件还可以理解与正常的生命周期一致,
状态怎么回事?是不是少了和onPause,onStop对应的paused,stoped状态?
事件转换为状态的源码如下:
public State getTargetState() {
switch (this) {
case ON_CREATE:
case ON_STOP:
return State.CREATED;
case ON_START:
case ON_PAUSE:
return State.STARTED;
case ON_RESUME:
return State.RESUMED;
case ON_DESTROY:
return State.DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException(this + " has no target state");
}
通过源码可以看出 状态CREATED
对应 事件ON_CREATE
,ON_STOP
。状态STARTED对应事件ON_START,ON_PAUSE。
Lifecycle内部持有当前Activity的状态,如果当前状态为STARTED
,那如何确定生命周期处于onStart
还是onStop
呢?
public class LifecycleRegistry extends Lifecycle {
//Current state
private State mState;
}
页面从打开到关闭就是页面的生命周期,对于用户的感受是:不可见—可见—不可见。
从原理图可以明显看出有两个流程:
- 不可见 到 可见 ,起个别名:打开流程
- 可见 到 不可见 ,起个别名:关闭流程
打开流程的状态更改:INITIALIZED
— CREATED
— STARTED
— RESUMED
关闭流程的状态更改:RESUMED
— STARTED
— CREATED
— DESTROYED
状态*CREATED
* 在打开流程则表示Activity生命周期处于onCreate
状态*CREATED
* 在关闭流程则表示Activity生命周期处于onStop
那么问题来了 如何根据状态 判断处于打开流程 还是 关闭流程呢?
涉及到关于枚举基础知识:
- 枚举成员的默认值是0,按照声明顺序+1
- 枚举调用****compareTo()****方法进行比较,相等返回0,大于返回正值,小于返回负值
状态枚举值比较
如果Lifecycle中保存的Activity当前状态大于LifecycleObserve的状态,表明是打开流程,页面可见
如果Lifecycle中保存的Activity当前状态小于LifecycleObserve的状态,表明是关闭流程,页面不可见
源码如下:
- upFrom 打开流程 状态转换事件
- downFrom 关闭流程 状态转换事件
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
}
public static Event upFrom(@NonNull State state) {
switch (state) {
case INITIALIZED:
return ON_CREATE;
case CREATED:
return ON_START;
case STARTED:
return ON_RESUME;
default:
return null;
}
}
public static Event downFrom(@NonNull State state) {
switch (state) {
case CREATED:
return ON_DESTROY;
case STARTED:
return ON_STOP;
case RESUMED:
return ON_PAUSE;
default:
return null;
}
}
虽然我捋清楚状态与事件的关系,但是不能明白为什么要这么设计,整出打开流程,关闭流程。还是太菜了 哈哈哈
4. LiveData简说
感知生命周期的观察者组件。号称关联的Activity销毁时会自动清理,永远不会发生内存泄漏;Activity处于非活跃状态时不会接收任何事件;自动管理生命周期等这些好用的特性都是根据Lifecycle实现的。
比如:
LiveData.observe()
开始就判断 如果Lifecycle的状态等于DESTROYED
直接return- 创建核心类 LifecycleBoundObserver 并添加到Lifecycle中 观测生命周期
shouldBeActive()
通过Lifecycle判断是否页面是否处于前台onStateChanged()
判断如果Lifecycle状态为*DESTROYED
* 直接移除观察者
LiveData.setValue()
给观察者分发值之前 通过shouldBeActive()
方法检测应用是否处于前台
Lifecycle搞的这么复杂就是为了让三方组件能够感知到生命周期,最典型的例子就是LiveData。
5.Lifecycle工作流程分析
在开始原理分析之前 回顾一下Lifecycle的诞生的意义:作为Activity与开发者之间的抽象层,能够更方便监听生命周期获取Activity状态
它使用大概有两种情况:
- 当Activity的生命周期改变,Lifecycle主动通知开发者自定义组件
- 当自定义组件有需求时通过Lifecycle获取Activity的状态
如果是我想要实现上述效果必须要解决的问题是:
- Activity,Fragment生命周期改变之后 如何通知Lifecycle
- 自定义组件获取通过Lifecycle获取Activity,Fragment的状态,这个状态是如何维护的
- 官方原理图表明Lifecycle通过内部维护的状态(States)切换发出事件(Event) 这套体系是如何运行的?如何保证一致性?
待着问题,源码分析的流程
- 在Activity子类中 通过
getLifecycle()
方法获取 lifecycle,实现类是LifecycleRegistry
。通过addObserver()
添加的自定义组件也是保存在LifecycleRegistry
内部 ComponentActivity
中private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
LifecycleRegister声明全局变量,通过构造函数持有Activity引用- 根据的问题猜想,Activity和 LifecycleRegister之前肯定存在某种通信方式。
- 可能是LifecycleRegister持有Activity的引用,通过某种手段获取到生命周期的变化
- 也可能是LifecycleRegister 公开方法,Activity在生命周期中调用
- 其他方式
- 通过进入LifecycleRegister源码,持有Activity类型是
LifecycleOwner
存储在全局变量mLifecycleOwner
中 - 先验证猜想 ” LifecycleRegister持有Activity的引用,通过某种手段获取到生命周期的变化“
LifecycleRegistry
源码并不复杂只有不到400行,通过全局搜索mLifecycleOwner(Activity)
只有在LifecycleRegistry.addObserver() 和 LifecycleRegistry.sync()
两个方法中用到。并且没有咱们猜想的 通过某种手段获取到Activity的生命周期变化。 所以这个猜想废弃了
- 那就可能是第二种猜想 ”LifecycleRegister 公开方法,Activity在生命周期中调用“
ComponentActivity
中搜索LifecycleRegistry
的调用。- 发现只有
getLifecycle()
一处调用,作为方法返回值 - 这就难办了 卡住了,
- 比较快的方式是 找个别人的源码分析,看看思路
- 慢慢的读一哈源码,因为
LifecycleRegistry
代码量并不大,按照咱们的猜想肯定是存在一个public方法供外部调用。重要的方法在源码中是留有注释的,能够查看方法作用 - 最终找到了
handleLifecycleEvent()
作用:设置当前状态,通知自定义组件状态改变 - 借助AndroidStudio,查找当前方法都在哪里调用
- 发现
handleLifecycleEvent()
在两个包下调用:- androidx.fragment.app
- androidx.lifecycle
- Fragment下的调用和
ComponentActivity
没什么关系,Lifecycle包下的调用都在ReportFragment
。而ReportFragment
在ComponentActivity.onCreate()
中调用静态方法。ReportFragment.*injectIfNeededIn*(this);
那么我们就看看ReportFragment
是如何实现的 - 在Activity调用onCreate时
ReportFragment
添加到Activity中,- 内部重写Fragment生命周期,
- 比如:在onStart()调用
dispatch(Lifecycle.Event.ON_START)
dispatch
方法内部调用LifecycleRegistry.handleLifecycleEvent
- 到此为止第一个问题得到答案
- Activity初始时,添加一个看不见的Fragment
ReportFragment
。 - 重写
ReportFragment
每个生命周期方法,改变时传递事件到LifecycleRegistry
- Activity初始时,添加一个看不见的Fragment
handleLifecycleEvent()
核心方法,承上启下。一方面对接activity,接收生命周期事件。另一方面接收事件后通知自定义组件。- 检查线程
handleLifecycleEvent(Lifecycle.Event)
的核心逻辑如下:- 外部传递的事件(Event) 转化为对应的状态
- 调用
moveToState()
见名知义,用作切换状态 - 如果事件转换的状态 与 内部状态一致 则return
- 标记
mHandlingEvent
当前是否正在进行 - 如果不一致 则调用 同步方法
sync()
进行状态同步,把最新的状态同步给观察者(自定义组件) sync()
内部 有while
循环语句while (!isSynced())
知道所有观察者的状态都一直才会结束循环
- 同步过程的关键就是上一章描述的事件与状态的关系
- 关闭流程 调用
backwardPass()
- 打开流程 调用
forwardPass()
- 两个方法内部实现几乎一致,根据所处流程判断状态对应的事件。
- 关闭流程中状态
STARTED
对应 事件ON_STOP
- 打开流程中状态*
STARTED
对应事件*ON_RESUME
- 状态转换事件的方法见
Lifecycle.Event.upFrom()
和Lifecycle.Event.downFrom()
- 关闭流程中状态
- 关闭流程 调用
backwardPass()
和forwardPass()
调用observer.dispatchEvent()
进行事件分发。最终会调用到LifecycleEventObserver.``onStateChanged()
。LifecycleEventObserver
观察者接口 也就是我们的自定义组件,逻辑完成!