【深入理解Kotlin协程】lifecycleScope源码追踪扒皮

本文深入探讨了Kotlin协程在Android环境中的应用,特别是生命周期(Lifecycle)如何影响协程的执行。文章揭示了`lifecycleScope`的实现细节,涉及到`LifecycleCoroutineScopeImpl`和`LifecycleRegistry`。内容包括Activity和Fragment如何通过LifecycleRegistry触发生命周期变化,以及这些变化如何影响协程的取消。通过对API 29以上和以下的生命周期回调处理的分析,阐述了Activity和Fragment中生命周期状态的变迁过程,以及最终如何调用`onStateChanged()`接口方法。
摘要由CSDN通过智能技术生成

lifecycleScopeLifecycleOwner的扩展属性,而  ComponentActivity 和  Fragment(androidx)都实现了  LifecycleOwner 接口,所以这就是为什么说 lifecycleScope的作用范围是只能在Activity、Fragment中使用。
public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
    get() = lifecycle.coroutineScope

其中LifecycleOwner.lifecycleScope返回的是LifecycleOwnergetLifecycle().coroutineScope, coroutineScope又是Lifecycle的扩展属性:

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

lifecycleScope返回的是一个LifecycleCoroutineScopeImpl对象,而LifecycleCoroutineScope则是一个使用 SupervisorJob() + Dispatchers.Main.immediate 作为协程上下文的CoroutineScope对象。

LifecycleCoroutineScopeImpl的源码:
internal class LifecycleCoroutineScopeImpl(
    override val lifecycle: Lifecycle,
    override val coroutineContext: CoroutineContext
) : LifecycleCoroutineScope(), LifecycleEventObserver {
    init {
        if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
            coroutineContext.cancel()
        }
    }

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

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

内部是通过  lifecycle.addObserver(this) 注册了 观察者对象,即将当前对象自身注册到了lifecycle对象中,当生命周期状态发生变化的时候,就会回调当前对象作为观察者的接口方法   onStateChanged() 。
     
在  onStateChanged() 方法中判断 lifecycle 当前的  state 如果小于等于  DESTROYED 就移除观察者并调用协程上下文的 cancel方法(这个方法中会查询当前上下文的Job对象调用其 cancel方法,从而取消协程)。
    
其中, Lifecycle.State是一个枚举类:
 public enum State {
     DESTROYED,   // 0
     INITIALIZED, // 1
     CREATED,     // 2
     STARTED,     // 3
     RESUMED;     // 4
     public boolean isAtLeast(@NonNull State state) {
         return compareTo(state) >= 0;
     }
 }

而 Activity和Fragment都实现了LifecycleOwner接口(可以通过getLifecycle()获取到Lifecycle的实例对象),在Activity和Fragment内部都实现了Lifecycle机制,Activity和Fragment对象中都有一个Lifecycle的实例对象LifecycleRegistry当Activity和Fragment生命周期函数变化时,会触发持有的Lifecycle实例对象的相关方法,改变对应的状态值,进而调用到其持有的观察者回调接口,即上面的LifecycleCoroutineScopeImpl对象里的onStateChanged()方法。并在其中判断如果是DESTROYED 状态就调用协程上下文的cancel方法取消协程。

因此, lifecycleScopeActivity执行 onDestroy()方法之后就会自动取消协程的原理真相就是如此。
      
我们说 lifecycleScope 只能在 Activity、Fragment 中使用其实是不太准确的。上面分析了  lifecycleScope是 LifecycleOwner 的扩展属性,Receiver 是 LifecycleOwner。因为Activity、Fragment和默认实现了LifecycleOwner,所以在其内部可以直接使用。但是理论上来说 只要是能获取到 LifecycleOwner 的地方都是可以使用 lifecycleScope 的!比如说从Activity、Fragment中创建的其他UI组件,只要是能获取Activity、Fragment对象的地方,那就可以间接地获取到LifecycleOwner。而像DialogFragment是Fragment的子类,自然也可以使用。
            
比如说LifecycleCoroutineScope内部就提供了几个方法, 当你不是在Activity、Fragment内部调用的时候,可以调用使用这几个方法:
public abstract class LifecycleCoroutineScope internal constructor() : CoroutineScope {
    internal abstract val lifecycle: Lifecycle
    public fun launchWhenCreated(block: suspend CoroutineScope.() -> Unit): Job = launch {
        lifecycle.whenCreated(block)
    }
    public fun launchWhenStarted(block: suspend CoroutineScope.() -> Unit): Job = launch {
        lifecycle.whenStarted(block)
    }
    public fun launchWhenResumed(block: suspend CoroutineScope.() -> Unit): Job = launch {
        lifecycle.whenResumed(block)
    }
}

内部其实是一个DispatchQueue封装了ArrayDeque队列。判断生命周期如果小于当前可执行的生命周期则加入队列,等到对应生命周期来到在取出执行。

但是有个问题就是使用这几个方法的时候没有办法设置异常处理器!直接启用了一个默认的launch,还没有给传入上下文的入口。 所以如果你想使用这几个方法还想传入异常处理器的话,可以这么做:自己写个launch。
val coroutineExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
    throwable.printStackTrace()
}
lifecycleScope.launch(coroutineExceptionHandler) {
    lifecycle.whenCreated {
        // TODO:  
    }
}

Lifecycle原理机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值