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() } }
- 作者:姜康
- 链接:https://jiangkang.tech/article/0cf00a15-a7e9-45b6-97ae-c82f76042a80
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章