理解 Lifecycle

说来惭愧,2021 年了才开始细看 Jetpack 的 Lifecycle,只因为之前项目里用 RxJava 实现的 Lifecycle 实在是太香了。

1. 为什么需要 Lifecycle?

一般一个新技术或者 idea 出现,都是为了解决一个具体的问题,或是开发中的痛点,那么 Lifecycle 想解决的问题是什么呢?

在上古时期,大家是把业务逻辑放在 Activity / Fragment 里的,随着代码量越来越大,可读性会变得越来越差,因为生命周期方法们,如 onStart() 这些是有限的,业务代码却是无限的。久而久之,这些回调就会被淹没在业务代码里。单个类中,即使只是包含一个页面的代码,也会变得非常庞大,结构混乱不便于维护,看都看不懂当然也更容易写出 bug 了。

于是慢慢出现了 MVP、MVVM 的所谓架构,通过让 Android Framework 与业务逻辑分离,把不同的业务逻辑拆分、细分,为的就是一部分代码只做一件事,做好一件事。至少代码结构是会清晰一些,但是总有些逻辑,是需要在生命周期回调里触发的,比如进入页面开始请求网络。所以仍然需要在 Activity 的回调里手动来触发。当需要手动调用的组件们比较多时,就会显得很繁琐,onStart 监听个东西,在 onStop 也总得取消不是?

2. Lifecycle 的解决方案

Lifecycle 给出的方案是,Activity 只负责分发生命周期变更,让这些不同的组件,自己去处理什么时候该触发对应方法。

此处盗用 Google 的一张图:

在 Android 中,具有生命周期的,是 Activity / Fragment 等,这些我们称之为 Lifecycle,其实严格意义上并不是它们,下文会讲到,此处只是从观察者模式来简单分类。我们的自定义组件,比如 ViewModel,希望获知生命周期变化,称之为 LifecycleObserver

2.1 使用

添加依赖

1implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.0"

当自定义组件希望能获知生命周期时,只需要实现 Lifecycle 接口,目前提供了 2 种方式:

2.1.1 LifecycleObserver

1class FooObserver : LifecycleObserver {
2    @OnLifecycleEvent(Lifecycle.Event.ON_START)
3    fun onStart() {
4        Timber.e("onStart")
5    }
6}

这只是个做标记的空接口,不用实现任何方法,通过 @OnLifecycleEvent(Lifecycle.Event.ON_START) 即可在希望的 Event 触发对应方法。

2.1.2 LifecycleEventObserver

1class BarObserver : LifecycleEventObserver {
2    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
3        if (event == Lifecycle.Event.ON_START) {
4            Timber.e("onStart")
5        }
6    }
7}

这种方式不使用注解,需要实现 onStateChanged 方法,所有的 Event 都会由这一个方法来处理。

不论上面哪种方式,在 Activity 对应的地方,注册一下就可以使用了:

1override fun onCreate(savedInstanceState: Bundle?) {
2    super.onCreate(savedInstanceState)
3    setContentView(R.layout.activity_main)
4
5    lifecycle.apply {
6        addObserver(FooObserver())
7        addObserver(BarObserver())
8    }
9}

那有了 addObserver,什么时候去 removeObserver 呢?

答案是不需要手动取消监听了。

很多地方有这样的疑问,比如 Lifecycle Observer is not removed in step_4

当我们在考虑取消注册时,一般是在担心内存泄漏。比如某个 Service 持有了 Activity 的 Context,那么当 Activity finish 后,因为仍然被其他对象引用,所以 GC 不能回收。在 Lifecycle 中没有这个问题,因为内部实现上,Activity 作为 LifecycleOwner 是被弱引用的。

2.2 奇怪的使用

有喜欢搞事情的同学可能会问了,这 2 个接口又不会冲突,我完全可以让一个类,实现上面这 2 种接口,就可以同时用两种风格来处理?

答案是不可以,实现 2 个接口,最终只会有 LifecycleEventObserver 生效,具体原因下文会谈到。

2.3 需要注意的 Case

2.3.1 Event 批量更新

因为 addObserver 是动态的,可以在任意地方注册,虽然通常我们都是在 onCreate 里。在任意地方注册可能带来的问题是,一个 LifecycleObserver 在监听 onStart,但是在 onResume 事件时才被注册,错过了 onStart 事件。这种情况在 Fragment 中尤为常见。

为了处理这个问题,在 addObserver 中,对应的 observer 会被一步一步更新到目前最新的状态。

1override fun onResume() {
2    super.onResume()
3    lifecycle.apply {
4        addObserver(FooObserver())
5    }
6}

上面的例子中,fooObserver 会依次收到 onCreate -> onStart -> onResume 3 个事件,即使 OnCreateonStart 已经发生在遥远的过去了,每个 lifecycleObserver 都会尽最大努力及时收到事件。

2.3.2 STOP 事件的时机

Android 在 Activity 的回收上,有点像是墓碑机制。通过 onSaveInstanceState 保存必要的数据,当需要重新创建时,使用当时保存的数据来恢复。

这带来了 2 个问题:

  1. onSaveInstanceStateonStop 时机并不是相等的,一般是在 onStop 之前,和具体的 API 版本有关。

  2. 在 API 23- 中, 如果一个 Activity 被另一个部分覆盖,不会调用 onStop,因为前一个 Activity 仍然部分可见,但是此时却有可能调用 onSaveInstanceState

Android 开发中,在 saveState 之后触发 UI 相关操作,很容易抛出异常,因为这之后的更改已经错过了保存的机会,等以后重建时,没有办法被恢复,也就是我们常说的 State Loss,为了保持较好的用户体验,离开时是什么样,就该恢复成什么样,不能被保存的操作算是打开方式不对,Android 系统很贴心地在一些 UI 操作时抛出 IllegalStateException,棒!

但是因为 onSaveInstanceStateonStop 之前,是极其不安全的,因为这个滞后性完全没有办法信任 onStop 了。

为了解决这个问题:

  1. Lifecycle 在内部实现上,onSaveInstanceStateonStop 时都分发了 Stop Event,作为一个补丁。

  2. Android P,即 API 28+ 上,onSaveInstanceState 放在了 onStop 之后,完全消除了这种不一致。

3. Lifecycle 内部实现

3.1 LifecycleObserver 们

为开发者暴露出来的只有上面提到的 2 种:

3.1.1 LifecycleEventObserver

通过实现接口方法处理 Event

1void onStateChanged(LifecycleOwner source, Lifecycle.Event event);

3.1.2 LifecycleObserver

通过注解,在对应 Event 触发方法

1@OnLifecycleEvent(Lifecycle.Event.ON_START)

需要注意的是,这种注解的方式,还可以细分为 2 种

  1. 如果添加了依赖:

    1kapt "androidx.lifecycle:lifecycle-compiler:2.3.0"
    

    那么在编译期,会生成新的类,比如一个简单的 LifecycleObserver

    1class FooObserver : LifecycleObserver {
    2    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    3    fun onStart() {
    4        Timber.e("onStart")
    5    }
    6}
    

    会生成下面的类,把注解转换成了普通的方法调用:

     1public class FooObserver_LifecycleAdapter implements GeneratedAdapter {
     2    final FooObserver mReceiver;
     3    FooObserver_LifecycleAdapter(FooObserver receiver) {
     4        this.mReceiver = receiver;
     5    }
     6
     7    @Override
     8    public void callMethods(LifecycleOwner owner, Lifecycle.Event event, boolean onAny, MethodCallsLogger logger) {
     9        boolean hasLogger = logger != null;
    10        if (onAny) {
    11            return;
    12        }
    13        if (event == Lifecycle.Event.ON_START) {
    14            if (!hasLogger || logger.approveCall("onStart", 1)) {
    15                mReceiver.onStart();
    16            }
    17            return;
    18        }
    19    }
    20}
    
  2. 如果没有添加上面的依赖,就不会生成新的类,只能使用反射运行时调用了。

3.2 Lifecycle 抽象类

Lifecycle 是一个抽象类,内部定义了上文提到的 Event 和 State,以及 addObserver / removeObserver 抽象方法。值得一提的是,State 是有序的,我们可以很容易地判断 2 个 State 的先后顺序:

1enum class State {
2    ...
3    
4    fun isAtLeast(state: State): Boolean {
5        return compareTo(state) >= 0
6    }
7}

3.3 LifecycleRegistry

上文提到,把 Activity / Fragment 当作 Lifecycle 是不严谨的,因为真正实现 Lifecycle 的其实是 LifecycleRegistry

首先,LifecycleRegistry 内部持有所有添加的 Observer 们:

1private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
2            new FastSafeIterableMap<>();

Key 是被添加的 Observer,Value 是内部定义的另一个类,如名字所言,带有实际的 State,下文会详细解释。

这个奇怪的 Map 实现了一个特性,比如我们依次添加 observer0, observer1, observer2,它可以保证任意时刻,observer0.state >= observer1.state >= observer2.state

通过严格要求这种关系,可以在 O(1) 的时间内,判断所有 Observer 们的 State 是不是都更新完毕了。

打个比方,在一个 LRU 缓存里,怎么判断是不是所有 item 访问次数都相同呢?

如果使用最多的 item 和使用最少的 item 访问次数是一样的,那么所有 item 的访问次数一定都一样。

这儿也是一样的道理:

1private boolean isSynced() {
2    if (mObserverMap.size() == 0) {
3        return true;
4    }
5    State eldestObserverState = mObserverMap.eldest().getValue().mState;
6    State newestObserverState = mObserverMap.newest().getValue().mState;
7    return eldestObserverState == newestObserverState && mState == newestObserverState;
8}

3.3.1 添加 LifecycleObserver

在添加 LifecycleObserver 时,只做了 2 件事:

  1. 把 LifecycleObserver 转换成 ObserverWithState 类型
  2. 把 Observer 的 State 更新到当前。

我们先只讲第 1 点,第 2 点需要和后面的分发 Event 一起讲。

 1static class ObserverWithState {
 2    State mState;
 3    LifecycleEventObserver mLifecycleObserver;
 4
 5    ObserverWithState(LifecycleObserver observer, State initialState) {
 6        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
 7        mState = initialState;
 8    }
 9
10    void dispatchEvent(LifecycleOwner owner, Event event) {
11        State newState = getStateAfter(event);
12        mState = min(mState, newState);
13        mLifecycleObserver.onStateChanged(owner, event);
14        mState = newState;
15    }
16}

这里需要注意的是最后一行,一个 Observer 的 State 变更,是在它的 onStateChanged 回调完成之后。

ObserverWithState 这个类也比较简单,需要分析的是 Lifecycling.lifecycleEventObserver(observer) 这里的实现:

 1static LifecycleEventObserver lifecycleEventObserver(Object object) {
 2    boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
 3    boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
 4    if (isLifecycleEventObserver && isFullLifecycleObserver) {
 5        return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
 6                (LifecycleEventObserver) object);
 7    }
 8    if (isFullLifecycleObserver) {
 9        return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
10    }
11    if (isLifecycleEventObserver) {
12        return (LifecycleEventObserver) object;
13    }
14 
15    final Class<?> klass = object.getClass();
16    int type = getObserverConstructorType(klass);
17    if (type == GENERATED_CALLBACK) {
18        List<Constructor<? extends GeneratedAdapter>> constructors =
19                sClassToAdapters.get(klass);
20        if (constructors.size() == 1) {
21            GeneratedAdapter generatedAdapter = createGeneratedAdapter(
22                    constructors.get(0), object);
23            return new SingleGeneratedAdapterObserver(generatedAdapter);
24        }
25        GeneratedAdapter[] adapters = new GeneratedAdapter[constructors.size()];
26        for (int i = 0; i < constructors.size(); i++) {
27            adapters[i] = createGeneratedAdapter(constructors.get(i), object);
28        }
29        return new CompositeGeneratedAdaptersObserver(adapters);
30    }
31    return new ReflectiveGenericLifecycleObserver(object);
32}

限于篇幅,就不贴各个 Observer 接口的细节了,这里我们可以看到优先顺序:

  1. FullLifecycleObserver

    实现各自的 onCreate / onStart / ... 最为高效

  2. LifecycleEventObserver

    实现统一的 onStateChanged 方法

  3. SingleGeneratedAdapterObserver / CompositeGeneratedAdaptersObserver

    添加了 lifecycle-compiler 依赖后,编译期自动生成的,也是方法调用

  4. ReflectiveGenericLifecycleObserver

    运行时反射调用

从上到下,效率越来越低,这也同时回答了上面的问题。我们自己的 ViewModel 同时实现 2 种 LifecycleObserver 接口,结果注解方法完全不会被调用,因为已经被忽略了。

3.2.2 分发 Event

Event 的分发,用的是普通的无 UI 的 ReportFragment 来处理,在 API29+ 时,直接监听 ActivityLifecycleCallbacks,否则用 Fragment 的回调来处理。

在 Event 分发中,存在一个棘手的问题,参考这里的注释:

1// we have to keep it for cases:
2// void onStart() {
3//     mRegistry.removeObserver(this);
4//     mRegistry.add(newObserver);
5// }
6// newObserver should be brought only to CREATED state during the execution of
7// this onStart method. our invariant with mObserverMap doesn't help, because parent observer
8// is no longer in the map.
9private ArrayList<State> mParentStates = new ArrayList<>();

一个 observer 是完全可以在回调里取消监听的。上文我们提到过,Observer 内部 State 的变更是在回调方法完成后才更新。那么这里在添加 childObserver 的时候,childObserver 的 State 是不能更新到最新的。

举个例子:在 parentObserver 的 onStart 里,childObserver 是不能直接更新到 STARTED 的,为什么呢? 如果 childObserver 直接更新到 STARTED,那就不能保证全局的 observerMap 的顺序了,作为最后添加的 observer,State 必须是最小的,为了上文说的在 O(1) 时间内判断是否 sync 完毕。

那就有人要问了,不是 parentObserver 都被移除了吗? 但是我们不能保证那时只有 parentObserver 处于 STARTED 前一个状态,也许还有其他的 Observer 正在等待处理同一个 onStart Event。

所以在添加 Observer 时,还有另一个方法来特殊处理应该更新到哪个 State:

1private State calculateTargetState(LifecycleObserver observer) {
2    Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
3    State siblingState = previous != null ? previous.getValue().mState : null;
4    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
5            : null;
6    return min(min(mState, siblingState), parentState);
7}

silbingState 就是普通的前一个 State,parentState 为了解决上面的移除问题。 通过小心翼翼地一步步更新,来保证 State 递减的特性。

另一个类似的处理是,在 Sync 时,需要遍历所有的 Observer,此时采用了不同的遍历顺序

 1private void sync() {
 2    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
 3    if (lifecycleOwner == null) {
 4        throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
 5                + "garbage collected. It is too late to change lifecycle state.");
 6    }
 7    while (!isSynced()) {
 8        mNewEventOccurred = false;
 9        // no need to check eldest for nullability, because isSynced does it for us.
10        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
11            backwardPass(lifecycleOwner);
12        }
13        Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
14        if (!mNewEventOccurred && newest != null
15                && mState.compareTo(newest.getValue().mState) > 0) {
16            forwardPass(lifecycleOwner);
17        }
18    }
19    mNewEventOccurred = false;
20}

无非还是为了能确保 observerMap 中 State 的单调性。

4. 总结

因为 Activity 的生命周期是现有的,所以 Lifecycle 的舞台比较小,并不需要去创造一个不存在的东西,所做的不过是包装得更易用一些。

从实现中,能学到不少:

  1. 使用双向链表,在 O(1) 时间判断当前状态是否同步完毕。
  2. 分发 Event 时考虑重入问题,如果不是真的自己来具体实现,恐怕很难意识到这个问题。