Jetpack实践指南:lifecycle与协程的"猫腻"事(一)

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

本篇文章主要是讲解如何使用lifecycle创建协程 、源码解析以及lifecycle在协程中的应用。

lifecycle创建协程

private fun test55() {
    //创建协程
    lifecycleScope.launch {

    }
}

如上很简单,如果想要和Activity的生命周期绑定,还有下面一系列方法供你使用:

private fun test55() {
    //创建协程
    lifecycleScope.launchWhenResumed {  }
    lifecycleScope.launchWhenCreated {  }
    lifecycleScope.launchWhenStarted {  }
}

只有当对应生命周期执行了,才会执行协程块中的代码。

lifecycleScope是什么

# LifecycleOwner.kt
val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
    get() = lifecycle.coroutineScope

通过调用链看到,它是lifecycle提供的一个扩展属性

val Lifecycle.coroutineScope: LifecycleCoroutineScope
    get() {
        while (true) {
            //1.
            val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?
            if (existing != null) {
                return existing
            }
            //2.
            val newScope = LifecycleCoroutineScopeImpl(
                this,
                SupervisorJob() + Dispatchers.Main.immediate
            )
            //3.
            if (mInternalScopeRef.compareAndSet(null, newScope)) {
                //4.
                newScope.register()
                return newScope
            }
        }
    }

1.mInternalScopeRef是lifecycle内部的一个属性:

AtomicReference<Object> mInternalScopeRef = new AtomicReference<>();

初次调用其get()方法肯定是一个空的,所以会走到2处。

2.创建一个LifecycleCoroutineScopeImpl对象,看下它是个啥:

image.png

再往下走:

image.png

可以看到这就是一个CoroutineScope的子类,所以我们这样就创建了一个协程作用域对象,并且指定:

  • job类型为SupervisorJob,这样子job间发生异常而不会互相影响,阻止向上传递异常;
  • 分发器类型为Dispatchers.Main.immediate,默认分发到主线程执行

在这里顺便说下Dispatchers.Main.immediateDispatchers.Main的区别:

首先这两个都是指定把协程块内容分发到主线程中执行,但是前者多了个immediate,这其实是一种优化手段,我们看下官方文档怎么说:

image.png

简单说,如果创建协程块的线程和要指定的调度线程都是主线程,使用immediate的就不需要额外使用分发器进行分发了,这算是一个优化小手段

3.将创建的这个协程作用域对象通过CAS写入lifecycle的mInternalScopeRef,这样当 lifecycleScope.launch在此获取协程作用域就不会进行重复创建了,直接从mInternalScopeRef获取即可。

综上所述, lifecycleScope就是个协程作用域对象,用来在特定job和主线程中执行协程块代码逻辑。

4.注册观察者,当界面销毁时取消所有协程的执行

image.png

LifecycleCoroutineScopeImpl本身就是观察者对象,所以看下register()就是注册观察者:

fun register() {
    launch(Dispatchers.Main.immediate) {
        if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
            lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
        } else {
            coroutineContext.cancel()
        }
    }
}

同时LifecycleCoroutineScopeImpl重写了onStateChanged()方法:

override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
    if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
        lifecycle.removeObserver(this)
        coroutineContext.cancel()
    }
}

就是为了方便当界面销毁了移除观察者,并取消所有的子协程代码块的执行,避免内存的泄漏。

总结

之后还会有一篇文章介绍协程是如何绑定Activity的生命周期,即lifecycleScope.launchWhenXXX{}lifecycle.repeatOnLifecycle(){}原理分析,了解两者的区别能帮助我们写出更加优雅的代码。

猜你喜欢

转载自juejin.im/post/7126685638622969892