携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情
前言
老项目升级了lifecycle之后发现以前的一些 LifecycleObserver 已经被标记过时,感慨一句,lifecycle的版本升级的真快。去年还能用的用法,今年已经过期。
今天简单的整理一下lifecycle的概念和一些用法。
Lifecycle 介绍
Lifecycle是一个生命周期感知组件,一般用来响应Activity、Fragment等组件的生命周期变化,并将变化通知到已注册的观察者。有助于更好地组织代码,让代码逻辑符合生命周期规范,减少内存泄漏,增强稳定性。这些组件可帮助您生成更易于组织且通常更轻量级的代码,这些代码更易于维护。
下面我们先介绍一下lifecycler的几个重点对象,他们是lifecycle的基石。
一、lifecycle的几个重要对象:
lifecycleRegister: lifecycle的唯一子类,用于在生命周期变化时触发自身状态和相关观察者的订阅回调逻辑,我们可以看看它的实现类基本上就是 Fragment 和 FragmentActivity 两个对象。
通过源码我们就可以查看到他们内部就是持有了 Register 对象。
它是主要的逻辑类,重点是获取Activity的生命周期,以及分发生命周期状态给包装适配器。
具体的观察代码大家可以搜索一下 ReportFragment ,其实内部的注释已经非常的详细了,高版本直接观察Activity的生命周期,低版本通过Fragment间接的观察Activity的生命周期。
具体的分发代码大家可以搜索一下 addObserver 内部的注释也是很详细,把状态分发给不同的适配器去实现。
LifecycleOwner: 连接生命周期的对象
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
它的接口实现基本就是 Fragment 和 FragmentActivity 两个对象。
getLifecycle的具体实现,就是返回上面初始化的 Register 对象。
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
LifecycleObserver: 观察者对象,通过 getLifecycle 获取到 Register 之后再通过 addObserver 方法添加指定的观察者对象。
具体的实现方式,有新旧的几种方式,又有谷歌推荐的方式,我们来看看如何使用 (本文的Lifecycle版本为2.4.1)
二、LifecycleObserver的实现
最简单的监听,应该都是这样直接使用 LifecycleObserver 的:
override fun init() {
lifecycle.addObserver(AutoDismiss())
}
主要是 AutoDismiss 的实现,一般我们都是直接实现接口:
这里故意使用的截图,可以看到标记为过期了,不推荐了。虽然如此我们之前版本都是这么用的,还是能用的。
三、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, 这一期就此草草完结。