当前位置:   article > 正文

Kotlin之协程coroutine lifecycleScope 和 viewModelScope源码(2)_kotlin lifecyclescope

kotlin lifecyclescope

上一篇文章 Kotlin之协程coroutine使用(1)  文末介绍了Activity,Fragment 和 ViewModelScope

对应的自动绑定生命周期协程开启方式, lifecycleScope  viewModelScope

这篇文章,就解剖一下,为什么这两货可以绑定生命周期,不需要用户自己去绑定取消?

=========================================================================

Activity 和 Fragment  对应的  lifecycleScope 

=========================================================================

先看一下 Activity 开启方式

  1. class CoroutinesActivity : AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_coroutines)
  5. // 通过 lifecycleScope 开启
  6. lifecycleScope.launch(Dispatchers.IO) {
  7. }
  8. }
  9. }

再看一下 Fragment 开启方式

  1. class CoroutinesFragment : Fragment() {
  2. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  3. super.onViewCreated(view, savedInstanceState)
  4. // viewLifecycleOwner.lifecycleScope
  5. viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
  6. }
  7. }
  8. }

点进去各自的 lifecycleScope 看一下,其实都是 androidx.lifecycle:lifecycle-runtime-ktx 包下的LifecycleOwner 对应的 lifecycleScope ,

可以看到是通过 lifeCycle  获得 coroutineScope,那究竟 lifeCycle  是怎么获得 coroutineScope,又是怎么将 coroutineScope 和生命周期绑定的,我们进去看一下

  1. /**
  2. * [CoroutineScope] tied to this [Lifecycle].
  3. *
  4. * This scope will be cancelled when the [Lifecycle] is destroyed.
  5. *
  6. * This scope is bound to
  7. * [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate]
  8. */
  9. public val Lifecycle.coroutineScope: LifecycleCoroutineScope
  10. get() {
  11. while (true) {
  12. //注释1 先判断是否已经有 coroutineScope ,有则直接返回
  13. val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?
  14. if (existing != null) {
  15. return existing
  16. }
  17. //注释2 没有创建一个 coroutineScope
  18. val newScope = LifecycleCoroutineScopeImpl(
  19. this,
  20. SupervisorJob() + Dispatchers.Main.immediate
  21. )
  22. //注释3 保存好 coroutineScope
  23. if (mInternalScopeRef.compareAndSet(null, newScope)) {
  24. //注释4 注册生命周期回调,绑定生命周期
  25. newScope.register()
  26. return newScope
  27. }
  28. }
  29. }
  30. //省略部分带码...
  31. internal class LifecycleCoroutineScopeImpl(
  32. override val lifecycle: Lifecycle,
  33. override val coroutineContext: CoroutineContext
  34. ) : LifecycleCoroutineScope(), LifecycleEventObserver {
  35. init {
  36. // in case we are initialized on a non-main thread, make a best effort check before
  37. // we return the scope. This is not sync but if developer is launching on a non-main
  38. // dispatcher, they cannot be 100% sure anyways.
  39. if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
  40. coroutineContext.cancel()
  41. }
  42. }
  43. fun register() {
  44. launch(Dispatchers.Main.immediate) {
  45. if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
  46. //注释4 注册生命周期回调,绑定生命周期
  47. lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
  48. } else {
  49. coroutineContext.cancel()
  50. }
  51. }
  52. }
  53. override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
  54. if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
  55. //注释5 当生命周期是 destroy 时,取消生命周期回调监听,取消协程
  56. lifecycle.removeObserver(this)
  57. coroutineContext.cancel()
  58. }
  59. }
  60. }

上面源码添加注释1.2.3.4.5 已经很明显了,整个流程是:

1:Activity 和 Fragment 获得的 都是通过 lifecycleScope  通过 LifecycleOwner 获得

2:这个 coroutineScope 是通过 LifecycleCoroutineScopeImpl 封装,这个 LifecycleCoroutineScopeImpl 同时实现了 LifecycleEventObserver CoroutineScope 接口。

3:所以(通过CoroutineScope )创建协程时,(通过LifecycleEventObserver )监听生命周期,当生命周期跑到destory时,取消监听并取消协程。

=========================================================================

ViewModel  对应的  viewModelScope 

=========================================================================

看下 ViewModel 怎么开启,viewModelScope  ViewModel  自有属性,直接调用即可

  1. import androidx.lifecycle.ViewModel
  2. import androidx.lifecycle.viewModelScope
  3. import kotlinx.coroutines.launch
  4. class MyViewModel : ViewModel() {
  5. fun test() {
  6. // 开启协程
  7. viewModelScope.launch {
  8. }
  9. }
  10. }

看下 viewModelScope   是怎么实现的

  1. package androidx.lifecycle
  2. import kotlinx.coroutines.CoroutineScope
  3. import kotlinx.coroutines.Dispatchers
  4. import kotlinx.coroutines.SupervisorJob
  5. import kotlinx.coroutines.cancel
  6. import java.io.Closeable
  7. import kotlin.coroutines.CoroutineContext
  8. private const val JOB_KEY = "androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY"
  9. /**
  10. * [CoroutineScope] tied to this [ViewModel].
  11. * This scope will be canceled when ViewModel will be cleared, i.e [ViewModel.onCleared] is called
  12. *
  13. * This scope is bound to
  14. * [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate]
  15. */
  16. val ViewModel.viewModelScope: CoroutineScope
  17. get() {
  18. /*
  19. * 注释1 每个ViewModel持有一个CoroutineScope
  20. * 初次获取创建并保存,保存通过Map 保存
  21. * 再次获取 直接返回
  22. * getTag() 和 setTagIfAbsent() 都是通过Map读写,有兴趣的可以进去细看
  23. */
  24. val scope: CoroutineScope? = this.getTag(JOB_KEY)
  25. if (scope != null) {
  26. return scope
  27. }
  28. return setTagIfAbsent(
  29. JOB_KEY,
  30. CloseableCoroutineScope(SupervisorJob()
  31. + Dispatchers.Main.immediate))
  32. }
  33. /**
  34. *注释 2
  35. *CloseableCoroutineScope 实现 CoroutineScope 和 Closeable
  36. *
  37. *CoroutineScope 实现协程功能
  38. *Closeable 实现关闭/取消协程功能
  39. *
  40. */
  41. internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
  42. override val coroutineContext: CoroutineContext = context
  43. override fun close() {
  44. //注释3: 取消协程
  45. coroutineContext.cancel()
  46. }
  47. }

看注释1.2.3.......知道ViewModel 怎么开启保存协程了,但是注释 3是取消协程的,到底什么时候调用的。要想知道什么时候调用,就要进入上面注释1,忽略的两个方法 getTag()setTagIfAbsent() 这个两方法对应有一个 叫:mBagOfTags 的 Map,

 看上面两个方法是看不出什么时候调用close()方法的,我们要看一下这个 mBagOfTags 还在其他什么地方/时候调用,在这个 ViewModel.java 里,我们很容易看到 mBagOfTags 有在 clear()方法里面调用

  1. public abstract class ViewModel {
  2. @Nullable
  3. private final Map<String, Object> mBagOfTags = new HashMap<>();
  4. @MainThread
  5. final void clear() {
  6. mCleared = true;
  7. // 注释1 清除 mBagOfTags 里面所有元素
  8. if (mBagOfTags != null) {
  9. synchronized (mBagOfTags) {
  10. for (Object value : mBagOfTags.values()) {
  11. // 注释2 close每一个元素
  12. closeWithRuntimeException(value);
  13. }
  14. }
  15. }
  16. onCleared();
  17. }
  18. private static void closeWithRuntimeException(Object obj) {
  19. if (obj instanceof Closeable) {
  20. try {
  21. // 注释3 close每一个元素
  22. ((Closeable) obj).close();
  23. } catch (IOException e) {
  24. throw new RuntimeException(e);
  25. }
  26. }
  27. }
  28. }

注释2 , 3 找到 close() 的地方。但是,我们是找到了关闭协程的地方,但是什么时候会调用 clear()

我们看一下 clear()引用的地方。

看到是通过 ViewModelStore 的 clear() 调用的。

发现通过Activity 和 Fragment 调用。笔者在跟其源码一步步找下去时,分别在Activity 和Fragment   destory时会触发他们对应的方法,去清除释放他们对应ViewModel 的 mBagOfTags 持有 数据。

至于这一部分,笔者就不贴代码追踪,因为不是本文要学习的内容。有兴趣的同学可以去看一下。

在这里笔者提醒一下,看源码不要转牛角尖,看个大概逻辑思路即可,要猜一半看一半,千万不要让自己把每一步代码搞懂,防止深陷源码不能自拔。

【总结】

 在这个再总结一下,ViewModel 会保存一个对应 ViewModelScope  ,初次获取时会保存在其mBagOfTags 的Map里面,再次获取会从这个 mBagOfTags 取出。当 ViewModel 宿主体(Activity 或 Fragment )销毁时,Activity 或 Fragment会通过 ViewModelStore,把 ViewModel 的 mBagOfTags 持有数据全部清除释放掉,当然协程就是在这个时候释放取消掉。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/495660
推荐阅读
相关标签
  

闽ICP备14008679号