Jetpack 之 Lifecycle

Jetpack 是 Google 官方力推的一个套件,它由许多库组成,这些库的出现意在帮助开发者简化业务逻辑之外的部分,包括开发架构优化、避免内存泄漏、性能优化等方面。之前我也零零散散用到过一些,现在准备做个记录,帮助自己梳理以及再次熟悉一下各组件。

首先回顾一下 Lifecycle。

一、Lifecycle 有什么用

Lifecycle,生命周期,从名字上来看就知道它与生命周期紧密相连,一提到生命周期,我们首先想到的就是 Activity、Fragment、Service 等。没错,Lifecycle 这个组件就是用来帮助我们更方便的做一些与生命周期绑定的操作,主要用于 Activity 或 Fragment 之间,androidx 下的 ComponentActivity 和 Fragment 已经默认实现了 LifecycleOwner。当然我们也可以自己实现 LifecycleOwner,但很少会有这样的需求。

我们日常开发中常常会在 Activity 的生命中做一些初始化资源和释放资源的操作,经典的 MVP 架构也是需要在 Activity 的生命周期中进行 v 层与 p 层的绑定解绑操作,这些操作呢主要是为了及时释放资源,避免内存泄漏,所以是必须注意的。但是要是这些操作全都写到 Activity 中,越来越多就会导致 Activity 臃肿,因此 Lifecycle 应运而生,帮助我们从 Activity 中剥离这些代码。

举个例子,我们在使用 MediaPlayer 的时候,通常需要在 onPause() 中暂停播放,在 onDestroy() 中释放播放器,如果我们使用 Lifecycle 来自定义一个播放器,就不需要在 Activity 的生命周期中做些操作了,只需要在创建播放器实例关联一下 LifecycleObserver 即可。

二、LifecycleObserver 怎么用

生命周期观察者,可以观察 Activity、Fragment 及其他 LifecycleOwner 的实现类,在它们对应的生命周期时可以感知到,进而做一些自己的操作,比如初始化资源、释放资源、开启动画、停止动画等。

LifecycleObserver 的使用其实很简单,首先在 gradle 的 dependencies 中添加依赖:

    def lifecycle_version = "2.4.0"
    // Lifecycles only (without ViewModel or LiveData)
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

然后定义一个实现观察者类,也就是我们的业务类,要实现观察生命周期有两种方式:

  1. 实现 LifecycleObserver 接口,在自己定义的方法上,加入 OnLifecycleEvent 注解,然后被观察者触发相应生命周期的时候就会调用对应的方法,但是这种方式已经被弃用了。
    package com.qinshou.jetpackdemo.lifecycle
    
    import androidx.lifecycle.*
    
    class TestLifecycleObserver : LifecycleObserver {
        companion object {
            private const val TAG = "TestLifecycleObserver"
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        fun init() {
            // do sth.
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun release() {
            // do sth.
        }
    }
  2. 实现 DefaultLifecycleObserver 接口,覆写它的 onCreate、onStart 等方法,被观察触发相应生命周期的时候会调用对应的方法:
    package com.qinshou.jetpackdemo.lifecycle
    
    import android.util.Log
    import androidx.lifecycle.DefaultLifecycleObserver
    import androidx.lifecycle.LifecycleOwner
    
    class TestLifecycleObserver : DefaultLifecycleObserver {
        companion object {
            private const val TAG = "TestLifecycleObserver"
        }
    
        override fun onCreate(owner: LifecycleOwner) {
            super.onCreate(owner)
            Log.i(TAG, "onCreate")
        }
    
        override fun onStart(owner: LifecycleOwner) {
            super.onStart(owner)
            Log.i(TAG, "onStart")
        }
    
        override fun onResume(owner: LifecycleOwner) {
            super.onResume(owner)
            Log.i(TAG, "onResume")
        }
    
        override fun onPause(owner: LifecycleOwner) {
            super.onPause(owner)
            Log.i(TAG, "onPause")
        }
    
        override fun onStop(owner: LifecycleOwner) {
            super.onStop(owner)
            Log.i(TAG, "onStop")
        }
    
        override fun onDestroy(owner: LifecycleOwner) {
            super.onDestroy(owner)
            Log.i(TAG, "onDestroy")
            owner.lifecycle.removeObserver(this)
        }
    }

从观察者的示例可以看出它的使用很简单,只需要实现一个接口,然后在对应方法做对应操作就行了,对应到实际开发中,我们就可以在 onPause 中做诸如停止动画,暂停播放,在 onDestroy 中做一些释放资源等操作。

三、LifecycleOwner 怎么用

一般情况下,我们需要观察有生命周期的对象都是 Activity 或者 Fragment,它们已经默认实现了 LifecycleOwner 接口,它们是怎么触发 Lifecycle 对应的生命周期方法的,一会儿再浅析一下,这里先示例一下如果我们需要自定义 LifecycleOwner 应该怎么去做。就个人经验来说,这种情况其实很少,因为如果我们要定义一个对象有生命周期的话,那它应该也是跟系统的生命周期有所关联的,所以应该还是逃不开 Activity 和 Fragment,这里仅了解一下 LifecycleOwner 怎么用就行了。

自定义一个类实现 LifecycleOwner 接口,然后在合适时机调用 LifecycleRegistry.handleLifecycleEvent() 处理相应生命周期即可:

package com.qinshou.jetpackdemo.lifecycle

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry

class TestLifecycleOwner : LifecycleOwner {
    private val lifecycleRegistry by lazy { LifecycleRegistry(this) }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }

    fun handleOnCreate() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }

    fun handleOnStart() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
    }

    fun handleOnResume() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    }

    fun handleOnPause() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    }

    fun handleOnStop() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
    }

    fun handleOnDestroy() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    }
}

我们想要让 LifecycleOwner 处于某个生命周期,只需要调用 handleLifecycleEvent() 传入即可。可以写几个按钮分别调用上面定义的方法,然后查看观察者对应的生命周期的方法回调。代码太简单这里就不贴了,文章底部会有 demo 项目的链接。

需要注意的是,当我们按照顺序(ON_CREATE->ON_START->ON_RESUME->ON_PAUSE->ON_STOP->ON_DESTROY)设置 LifecycleOwner 的生命周期的时候没问题,设置哪个生命周期,观察者对应的方法就会回调,但是当:

  1. 我们重复设置同一个生命周期的时候,只有第一次会回调;
  2. 跳跃设置生命周期,比如从 ON_CREATE 直接到 ON_RESUME,或者从 ON_CREATE 直接到 ON_PAUSE,甚至往回设置之前的生命周期的时候,比如从 ON_RESUME 设置到 ON_CREATE 时,回调的并不是设置的那个生命周期。

这两点其实可以理解,在 Activity 中处于某个生命周期的时候,该生命周期也不会重复回调。而且 Activity 都是成对的,都是顺序调用的,所以不存在跨周期的情况。当我们自定义 LifecycleOwner 这样去干的时候,代码里面是怎么去拦截的呢?其实很简单,会有一个生命周期同步的步骤,查看 handleLifecycleEvent() 方法的源码:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    enforceMainThreadIfNeeded("handleLifecycleEvent");
    moveToState(event.getTargetState());
}


这个方法里面强制要求切换生命周期必须在主线程中,然后通过 event 去获取对应的 state:

public Lifecycle.State getTargetState() {
    switch (this) {
	    // ON_CREATE 和 ON_STOP 其实是同一个 State
        case ON_CREATE:
        case ON_STOP:
            return Lifecycle.State.CREATED;
	    // ON_START 和 ON_PAUSE 其实是同一个 State
        case ON_START:
        case ON_PAUSE:
            return Lifecycle.State.STARTED;
        case ON_RESUME:
            return Lifecycle.State.RESUMED;
        case ON_DESTROY:
            return Lifecycle.State.DESTROYED;
        case ON_ANY:
            break;
    }
    throw new IllegalArgumentException(this + " has no target state");
}

再调用了 moveToState() 方法:

private void moveToState(Lifecycle.State next) {
    if (mState == next) {
        return;
    }
    mState = next;
    // 如果正在处理生命周期,直接 return
    if (mHandlingEvent || mAddingObserverCounter != 0) {
        mNewEventOccurred = true;
        // we will figure out what to do on upper level.
        return;
    }
    mHandlingEvent = true;
    sync();
    mHandlingEvent = false;
}

这个方法里面比较重要的就是 sync() 方法,就是在这个方法里面,来决定处于某个生命周期时,如何去分发回调各观察者的:

    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
        while (!isSynced()) {
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
            Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

该方法中会将要设置的生命周期与最早和最新的生命周期比较,进行一个顺推和逆推,在顺推和逆推的过程再去回调各观察者的,如果设置的生命周期一样,就不会进行这个过程,所以也就不会重复调用了,也就解决了第一个疑问。
如果我们之前设置的 ON_PAUSE,按照 getTargetState() 方法当前应该处于 STARTED 状态,这时候再设置 ON_CREATE,那按照 getTargetState() 方法就应该设置为 CREATED 状态,但是明显 CREATED 是要早于 STARTED,所以会进入 backwardPass 方法进行一个逆推:

    private void backwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
                mObserverMap.descendingIterator();
        while (descendingIterator.hasNext() && !mNewEventOccurred) {
            Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
            ObserverWithState observer = entry.getValue();
            while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                    && mObserverMap.contains(entry.getKey()))) {
                Event event = Event.downFrom(observer.mState);
                if (event == null) {
                    throw new IllegalStateException("no event down from " + observer.mState);
                }
                pushParentState(event.getTargetState());
                observer.dispatchEvent(lifecycleOwner, event);
                popParentState();
            }
        }
    }

逆推中关注一下 downFrom() 方法,该方法传入的是 observer 当前的状态,按照上面的假设,传入的应该是 STARTED:

        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;
            }
        }

可以看到在这个方法中,如果是 STARTED,那逆推的结果应该是 ON_STOP,所以当我们处于 ON_PAUSE 状态的时候设置 ON_CREATE 的话,实际上回调的应该是 ON_STOP 这个生命周期对应的方法,这也就解决了第二个疑问。
顺推的过程类似,就不举例了。

四、为什么在 onResume 中 addObserver 还会回调 onCreate()

通常来说,我们会在界面创建的时候就添加观察者,也就是在 onCreate() 中去添加,但是当我们在 onResume() 甚至写一个按钮等待页面创建完成后再点击按钮去添加观察者,这时候会发现 onCreate()、onStart()、onResume() 都回调了,这相当于之前的回调都是粘性事件了,这是怎么回事呢?

这个问题的原因还得在源码中去寻找答案,一切都从添加观察者起,那就先看看 addObserver() 方法:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");
    Lifecycle.State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    // 创建一个 ObserverWithState 对象,只要被观察者没有处于 DESTROYED 状态,则 initialState 为 INITIALIZED
    LifecycleRegistry.ObserverWithState statefulObserver = new LifecycleRegistry.ObserverWithState(observer, initialState);
    // 检查之前是否有添加过该观察者,如果有则直接 return
    LifecycleRegistry.ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    if (previous != null) {
        return;
    }
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        // it is null we should be destroyed. Fallback quickly
        return;
    }

    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    Lifecycle.State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    // 会比较 statefulObserver 的当前状态和目标状态,如果目标状态此时为 RESUMED,则
    // statefulObserver 当前状态为 INITIALIZED,必然会进这个循环里面
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        // 根据 statefulObserver 当前状态决定 Event,upFrom() 方法在下面贴出
        final Lifecycle.Event event = Lifecycle.Event.upFrom(statefulObserver.mState);
        if (event == null) {
            throw new IllegalStateException("no event up from " + statefulObserver.mState);
        }
        // 分发事件,并在该方法中给 statefulObserver 的 mState 属性重新赋值
        statefulObserver.dispatchEvent(lifecycleOwner, event);
        popParentState();
        // mState / subling may have been changed recalculate
        targetState = calculateTargetState(observer);
    }

    if (!isReentrance) {
        // we do sync only on the top level.
        sync();
    }
    mAddingObserverCounter--;
}
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;
    }
}

从这两个方法中就可以明白了,如果被观察对象处于 RESUMED 状态,此时添加一个观察者,则它的默认状态为 INITIALIZED,而目标状态又是 RESUMED,那就会进入 while 循环中,第一次循环根据观察者的 INITIALIZED 状态,返回的 Event 为 ON_CREATE,然后通过 dispatchEvent () 方法回调观察者的 onCreate() 方法,在 dispatchEvent() 方法中又会通过 event 给 statefulObserver 的 mState 属性重新赋值(参考上面的 getTargetState() 方法),此时赋值为 CREATED,仍然比 RESUMED,继续循环,直到 statefulObserver 的 mState 与目标状态一样为止。

所以就算后添加的观察者,只要被观察者没有被销毁,那么从 INITIALIZED 被观察者的当前状态之间的生命周期对应的回调都会走一遍。

五、Activity 与 Fragment 中如何使用 Lifecycle 的

上面说到 LifecycleOwner 去设置生命周期的话是调用 LifecycleRegistry.handleLifecycleEvent() 方法,所以要想知道 Activity 和 Fragment 中如何去设置生命周期,其实看看源码,看看它们何时调用这个方法,也很容易找到,这里简单提一下吧。Activity 的话是由 ComponentActivity 实现了 LifecycleOwner 接口,也创建了 LifecycleRegistry 对象,但是它没有直接去操作该对象,在 ComponentActivity 的 onCreate() 中,创建了一个无界面的 ReportFragment,顾名思义,这个 Fragment 是用来上报状态的。

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedStateRegistryController.performRestore(savedInstanceState);
    ReportFragment.injectIfNeededIn(this);
    if (mContentLayoutId != 0) {
        setContentView(mContentLayoutId);
    }
}

Activity 的生命周期分发就是在 ReportFragment 中完成的,这里就不贴代码了,ReportFragment 会在各生命周期调用 dispatch() 方法去分发生命周期事件。

Fragment 直接实现了 LifecycleOwner 接口,但是它也不是自己直接调用,而是由 FragmentManagerImpl 来管理,这个类比较复杂,一两句说不清,限于篇幅就不展开说了,最开始的触发点是 FragmentTransaction 的 commit,有兴趣的可以往下追一下。

六、总结

Lifecycle 应该算是 Jetpack 中比较简单的一个组件,实现和使用都比较简单,也不太会存在需要自定义场景,但是它对我们减少内存泄漏却有很大帮助。

七、Demo 地址

禽兽先生/JetpackDemo-Lifecyclehttps://gitee.com/MrQinshou/jetpack-demo/tree/master/app/src/main/java/com/qinshou/jetpackdemo/lifecycle

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值