使用协程,相信很多同学已经信手拈来了,但是也有很多同学是不知道LifecycleScope
的。
LifecycleScope
,顾名思义,具有生命周期的协程。
它是LifecycleOwner
生命周期所有者的扩展属性,与LifecycleOwner生命周期绑定,并会在LifecycleOwner生命周期destroyed
的时候取消掉。
推荐理由:
内存泄漏
,可以替代MainScope。生命周期
执行。后面会重点介绍LifecycleScope是怎么做到的。
LifecycleScope虽然是协程,但属于Lifecycle中的
扩展属性
。
lifecycleScope默认
主线程
,可以通过withContext
来指定线程。
whenResumed
和launchWhenResumed
执行时机一样,区别在于:
共有三个对应生命周期的扩展函数:
使用非常简单,关键在于它是怎么保证不会内存泄露的,又是怎么知道在某个生命周期的时候去执行协程的?
先看lifecycleScope
源码:
继承自LifecycleCoroutineScope
,而LifecycleCoroutineScope是CoroutineScope
的子类(协程层级关系)。
get()返回lifecycle.coroutineScope
这里有一个源码小技巧,当继承对象与返回对象不一致时,那么返回对象多半为继承对象的子类。
继续看lifecycle.coroutineScope:
果不其然,也是继承LifecycleCoroutineScope。
关键在于,通过LifecycleCoroutineScopeImpl
创建了协程,默认主线程
,随后又调用了newScope.register()
继续看LifecycleCoroutineScopeImpl:
在register()
方法中添加了LifecycleEventObserver接口的监听,LifecycleEventObserver会在onStateChanged
方法中派发当前生命周期,关键来了,在onStateChanged回调中,判断当前生命周期是destroyed
的时候,移除监听,并取消协程
。
至此,相信大部分同学都明白了为什么不会造成内存泄露
了,因为在页面destroyed的时候,协程会取消,并不会继续执行,而MainScope
是需要手动取消的,否则会有内存泄露的风险。
插曲,我们进一步思考,在其他的开发场景中,也可以学习源码通过添加LifecycleEventObserver监听的方式,做回收清理操作,来避免内存泄漏。
author:yechaoa
以lifecycleScope.launchWhenResumed
为例,一探究竟。
调用whenResumed
:
接着调用whenStateAtLeast
,并传入一个具体生命周期状态作为标识
。
继续看whenStateAtLeast:
这里创建了LifecycleController
,并向下传入接收的具体状态,同时还有一个调度队列dispatcher.dispatchQueue。
接着看LifecycleController:
在init
初始化的时候,添加LifecycleEventObserver监听(又是一个使用案例,不过这里用的是lambda写法)。
在回调中,对生命周期进行了判断,当大于当前状态的时候,也就是生命周期执行到当前状态的时候,会调用dispatchQueue.resume()
执行队列,也就是协程开始执行
。
dispatchQueue.resume:
关于怎么获取到当前生命周期状态的,就涉及到Lifecycle
相关的知识了,简而言之,不管是Activity
还是Fragment
,都是LifecycleOwner
,其实是父类实现的,比如ComponentActivity。
在父类中通过ReportFragment
或ActivityLifecycleCallbacks
接口来派发当前生命周期状态,具体使用哪种派发方式要看Api
等级是否在29(10.0)及以上,及 则后者。
验证一下我们的分析是否正确。
代码简单测试:
同时对源码进行debug
。
通过打印,并结合断点执行顺序来看,以上分析是完全正确
的。
我们再来总结一下lifecycleScope
协程执行时机的流程。
以上,就是lifecycleScope
的使用,以及执行流程的具体分析。