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


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

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

    1. public val Lifecycle.coroutineScope: LifecycleCoroutineScope
    2.     get() {
    3.         while (true) {
    4.             val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?
    5.             if (existing != null) {
    6.                 return existing
    7.             }
    8.             val newScope = LifecycleCoroutineScopeImpl(
    9.                 this,
    10.                 SupervisorJob() + Dispatchers.Main.immediate
    11.             )
    12.             if (mInternalScopeRef.compareAndSet(null, newScope)) {
    13.                 newScope.register()
    14.                 return newScope
    15.             }
    16.         }
    17.     }

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

    LifecycleCoroutineScopeImpl的源码:
    1. internal class LifecycleCoroutineScopeImpl(
    2.     override val lifecycle: Lifecycle,
    3.     override val coroutineContext: CoroutineContext
    4. ) : LifecycleCoroutineScope(), LifecycleEventObserver {
    5.     init {
    6.         if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
    7.             coroutineContext.cancel()
    8.         }
    9.     }
    10.     fun register() {
    11.         launch(Dispatchers.Main.immediate) {
    12.             if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
    13.                 lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
    14.             } else {
    15.                 coroutineContext.cancel()
    16.             }
    17.         }
    18.     }
    19.     override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
    20.         if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
    21.             lifecycle.removeObserver(this)
    22.             coroutineContext.cancel()
    23.         }
    24.     }
    25. }

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

    而 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内部调用的时候,可以调用使用这几个方法:
    1. public abstract class LifecycleCoroutineScope internal constructor() : CoroutineScope {
    2.     internal abstract val lifecycle: Lifecycle
    3.     public fun launchWhenCreated(block: suspend CoroutineScope.() -> Unit): Job = launch {
    4.         lifecycle.whenCreated(block)
    5.     }
    6.     public fun launchWhenStarted(block: suspend CoroutineScope.() -> Unit): Job = launch {
    7.         lifecycle.whenStarted(block)
    8.     }
    9.     public fun launchWhenResumed(block: suspend CoroutineScope.() -> Unit): Job = launch {
    10.         lifecycle.whenResumed(block)
    11.     }
    12. }

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

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

    Lifecycle原理机制

  • 相关阅读:
    对进程的初步认识以及fork()函数的理解
    逆向-还原代码之url_encode (Interl 32)
    《LeetCode力扣练习》代码随想录——字符串(KMP算法学习补充——针对next数组构建的回退步骤进行解释)
    Delaunay三角网之逐点插入法(优化版本三)
    模型剪枝-Network Slimming算法分析
    双位置继电器DLS-42/6-4/DC110V
    Vue模板语法集(上)
    CSS:弹性布局(display:flex)
    如何在 pyqt 中实现桌面歌词
    自定义样式与模板
  • 原文地址:https://blog.csdn.net/lyabc123456/article/details/127866410