Lifecycle的简单介绍与几种使用方式

1,517 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情

前言

老项目升级了lifecycle之后发现以前的一些 LifecycleObserver 已经被标记过时,感慨一句,lifecycle的版本升级的真快。去年还能用的用法,今年已经过期。

今天简单的整理一下lifecycle的概念和一些用法。

Lifecycle 介绍

Lifecycle是一个生命周期感知组件,一般用来响应Activity、Fragment等组件的生命周期变化,并将变化通知到已注册的观察者。有助于更好地组织代码,让代码逻辑符合生命周期规范,减少内存泄漏,增强稳定性。这些组件可帮助您生成更易于组织且通常更轻量级的代码,这些代码更易于维护。

下面我们先介绍一下lifecycler的几个重点对象,他们是lifecycle的基石。

一、lifecycle的几个重要对象:

lifecycleRegister: lifecycle的唯一子类,用于在生命周期变化时触发自身状态和相关观察者的订阅回调逻辑,我们可以看看它的实现类基本上就是 Fragment 和 FragmentActivity 两个对象。

通过源码我们就可以查看到他们内部就是持有了 Register 对象。

image.png

它是主要的逻辑类,重点是获取Activity的生命周期,以及分发生命周期状态给包装适配器。

具体的观察代码大家可以搜索一下 ReportFragment ,其实内部的注释已经非常的详细了,高版本直接观察Activity的生命周期,低版本通过Fragment间接的观察Activity的生命周期。

具体的分发代码大家可以搜索一下 addObserver 内部的注释也是很详细,把状态分发给不同的适配器去实现。

LifecycleOwner: 连接生命周期的对象

public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle();
}

它的接口实现基本就是 Fragment 和 FragmentActivity 两个对象。

image.png

getLifecycle的具体实现,就是返回上面初始化的 Register 对象。

    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

LifecycleObserver: 观察者对象,通过 getLifecycle 获取到 Register 之后再通过 addObserver 方法添加指定的观察者对象。

具体的实现方式,有新旧的几种方式,又有谷歌推荐的方式,我们来看看如何使用 (本文的Lifecycle版本为2.4.1)

二、LifecycleObserver的实现

最简单的监听,应该都是这样直接使用 LifecycleObserver 的:

    override fun init() {

        lifecycle.addObserver(AutoDismiss())

    }

主要是 AutoDismiss 的实现,一般我们都是直接实现接口:

image.png

这里故意使用的截图,可以看到标记为过期了,不推荐了。虽然如此我们之前版本都是这么用的,还是能用的。

三、LifecycleEventObserver的实现

class AutoDismiss : LifecycleEventObserver {

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {

        if (event == Lifecycle.Event.ON_DESTROY) {
            YYLogUtils.w("销毁吧")
        }

    }

}

相当于是直接把 LifecycleRegistry 中的时间过继了一次,

   LifecycleEventObserver mLifecycleObserver;

     void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = event.getTargetState();
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }

就是使用这种方法需要我们在 onStateChanged 中手动的判断具体的生命周期判断了。

四、DefaultLifecycleObserver的实现

DefaultLifecycleObserver 实现的又是 FullLifecycleObserver 全生命周期的回调,FullLifecycleObserver 是私有的,并且实现起来并不方便,我们一般都是实现 DefaultLifecycleObserver 接口,它内部进行了默认的空实现,我们可以有选择的对需要的生命周期进行重写。

class AutoDismiss : DefaultLifecycleObserver {
    
    override fun onDestroy(owner: LifecycleOwner) {
        YYLogUtils.w("销毁吧")
    }

}

这个也是最简单的一种实现。也是个人比较推荐的一种写法。

五、Lifecyle的实战应用

我们可以使用Lifecycle把Activity中需要感知生命周期的一些方法库分离出去,避免了Activity的臃肿,并且解耦了逻辑。

例如我们使用动画工具类,我们就可以使用Lifecycle绑定动画执行的生命周期,让页面Destory的时候取消动画执行,释放资源:

class AsyncAnimUtil private constructor() : DefaultLifecycleObserver {

    private var mHandlerThread: HandlerThread? = HandlerThread("anim_run_in_thread")

    private var mHandler: Handler? = mHandlerThread?.run {
        start()
        Handler(this.looper)
    }

    private var mOwner: LifecycleOwner? = null
    private var mAnim: ViewPropertyAnimator? = null

    companion object {
        val instance: AsyncAnimUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            AsyncAnimUtil()
        }
    }

    //启动动画
    fun startAnim(owner: LifecycleOwner?, animator: ViewPropertyAnimator) {
        try {
            if (mOwner != owner) {
                mOwner = owner
                addLoopLifecycleObserver()
            }

            if (mHandlerThread?.isAlive != true) {
                YYLogUtils.w("handlerThread restart")
                mHandlerThread = HandlerThread("anim_run_in_thread")
                mHandler = mHandlerThread?.run {
                    start()
                    Handler(this.looper)
                }
            }

            mHandler?.post {
                mAnim = animator.setListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator?) {
                        super.onAnimationEnd(animation)
                        destory()
                    }

                    override fun onAnimationCancel(animation: Animator?) {
                        super.onAnimationCancel(animation)
                        destory()
                    }

                    override fun onAnimationEnd(animation: Animator?, isReverse: Boolean) {
                        super.onAnimationEnd(animation, isReverse)
                        destory()
                    }
                })
                mAnim?.start()
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    // 绑定当前页面生命周期
    private fun addLoopLifecycleObserver() {
        mOwner?.lifecycle?.addObserver(this)
    }

    // 退出页面的时候释放资源
    override fun onDestroy(owner: LifecycleOwner) {
        YYLogUtils.i("AsynAnimUtil Lifecycle -> onDestroy")
        mAnim?.cancel()
        destory()
    }

    private fun destory() {
        YYLogUtils.w("handlerThread quit")

        try {
            mHandlerThread?.quitSafely()

            mAnim = null
            mOwner = null
            mHandler = null
            mHandlerThread = null
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

}

使用的时候绑定生命周期即可

    val anim = mBinding.ivAnim.animate()
        .scaleX(2f)
        .scaleY(2f)
        .translationXBy(200f)
        .translationYBy(200f)
        .setDuration(2000)

    AsyncAnimUtil.instance.startAnim(this, anim)

还有一些经典的例子,比如绑定自定义协程的生命周期,例如一些viewModelScope,lifecycleScope 我们都知道他们都和生命周期绑定了的,如果我们想在一个 Utils 或者 Dialog 中使用自定义协程,我们又怎么绑定生命周期呢?是的我们需要lifecycle来帮助我们实现。

自定义协程生命周期的绑定

class LoginInterceptCoroutinesManager private constructor() : DefaultLifecycleObserver, CoroutineScope by MainScope() {

    companion object {
        private var instance: LoginInterceptCoroutinesManager? = null
            get() {
                if (field == null) {
                    field = LoginInterceptCoroutinesManager()
                }
                return field
            }

        fun get(): LoginInterceptCoroutinesManager {
            return instance!!
        }
    }

    private lateinit var mCancellableContinuation: CancellableContinuation<Boolean>

    fun checkLogin(loginAction: () -> Unit, nextAction: () -> Unit) {

        launch {

            if (LoginManager.isLogin()) {
                nextAction()
                return@launch
            }

            loginAction()

            val isLogin = suspendCancellableCoroutine<Boolean> {

                mCancellableContinuation = it

                YYLogUtils.w("暂停协程,等待唤醒")
            }


            YYLogUtils.w("已经恢复协程,继续执行")
            if (isLogin) {
                nextAction()
            }
    }

    fun loginFinished() {
        if (!this@LoginInterceptCoroutinesManager::mCancellableContinuation.isInitialized) return

        if (mCancellableContinuation.isCancelled) return

        mCancellableContinuation.resume(LoginManager.isLogin(), null)


    }

    //页面销毁的时候取消协程
    override fun onDestroy(owner: LifecycleOwner) {
        YYLogUtils.w("LoginInterceptCoroutinesManager - onDestroy")
        mCancellableContinuation.cancel()
        cancel()
    }

}

比如上面的Utils工具类中,我们的协程就可以绑定到页面的生命周期,这也是它的一个应用场景。

诸如此类的使用场景还有很多,比如Http的请求,视频的播放暂停,Banner的自动轮播与停止等等。这里就不一一展示。

总结

lifecycle是基于观察者模式实现的,不管是lifecycle还是观察者模式在应用开发的过程中是非常常见的,可以说日常开发都离不开他们。

配合一些工具类,协程可以很方便的解耦逻辑,让你的代码更"好看"。

还好老项目升级之后改动的量还不算不大,我已经把之前的过期方式都改掉了,但是一些第三方库里面的过期方法还是没有办法修改,索性目前还能用,懒得改了,就这样吧...

Ok, 这一期就此草草完结。