type
status
date
slug
summary
tags
category
icon
password

简单说明

CoroutineScope其实定义了协程的生命周期,比如在Activity中启动的协程,在Activity销毁的时候应该要取消.
而GlobalScope则是对应整个APP的生命周期,即使Activity已经销毁,CoroutineScope依然继续运行,可能导致协程泄漏,内存泄漏.

CoroutineScope

先来看一下它的定义:
public interface CoroutineScope { // 不建议使用普通的代码访问这个属性,除非使用Job()用于一些高级使用场景 // 按照约定,这个属性应该包含一个Job对象用于强制执行结构化并发,比如可以这么用coroutineContext[Job] public val coroutineContext: CoroutineContext }
可以看到,就是一个只带一个Field的简单接口.
CortoutineScope中封装了CoroutineContext,用于各种CortoutineScope的extention方法,比如GlobalScope.launch.
可以使用诸如下面这样的代码去创建CoroutineScope:
private val job = Job() val coroutineScope = CoroutineScope(Dispatchers.Main + job)
再比如ViewModel提供的协程实现:
val ViewModel.viewModelScope: CoroutineScope get() { val scope: CoroutineScope? = this.getTag(JOB_KEY) if (scope != null) { return scope } return setTagIfAbsent(JOB_KEY, CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)) } internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope { override val coroutineContext: CoroutineContext = context override fun close() { coroutineContext.cancel() } }
这里都会对CoroutineContext进行 +操作,这里其实就是一个操作符重载.
public operator fun plus(context: CoroutineContext): CoroutineContext = if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation context.fold(this) { acc, element -> val removed = acc.minusKey(element.key) if (removed === EmptyCoroutineContext) element else { // make sure interceptor is always last in the context (and thus is fast to get when present) val interceptor = removed[ContinuationInterceptor] if (interceptor == null) CombinedContext(removed, element) else { val left = removed.minusKey(ContinuationInterceptor) if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else CombinedContext(CombinedContext(left, element), interceptor) } } }

创建自定义的CoroutineScope

  • 使用CoroutineScope()方法
    • fun createScope(){ CoroutineScope(Dispatchers.Main).launch { // doSomething() } }
      这里的CoroutineScope是一个方法:
      public fun CoroutineScope(context: CoroutineContext): CoroutineScope = ContextScope(if (context[Job] != null) context else context + Job())
      需要注意的是,在组件生命周期结束时记得cancel操作

如果不使用GlobalScope,使用什么Scope?

如果不想自己自定义CoroutineScope,可以有下面这些选择:
  • 使用MainScope
    • class MyAndroidActivity { private val scope = MainScope() override fun onDestroy() { super.onDestroy() scope.cancel() } }
      这里的MainScope其实也是一个简单的拓展实现:
      public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)
      注意到这里使用的是Dispatchers.Main,因此不要在里面做耗时操作.可以与withContext()方法组合使用.
  • 使用AndroidX提供的ViewModelScope等.
    • val ViewModel.viewModelScope: CoroutineScope get() { val scope: CoroutineScope? = this.getTag(JOB_KEY) if (scope != null) { return scope } return setTagIfAbsent(JOB_KEY, CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)) } internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope { override val coroutineContext: CoroutineContext = context override fun close() { coroutineContext.cancel() } }
浅谈Android中的BroadcastKotlin中的协程
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏