本篇文章解析Kotlin协程的CoroutineScope, CoroutineContext及其继承类, 旨在探讨并理解kotlin的协程使用,以及对各个协程api细节整理。html
关于协程跨平台的实现以及跨平台使用介绍,欢迎去个人博客:编译以后--Kotlin 跨平台协程看看,或者去看看官方的视频&ppt,这也是我本篇文章的基础:git
这篇文章好久前就已经打好了草稿,可是因为最近忙没有时间写,再加上最近都没有在写Kotlin。今天仔细又读了一些文档、源码,为了整理一下本身的思路,将本身的我的理解写在这里。github
本文的前提是读者了解协程基本使用,见官方中文文档api
注:Kotlin版本迭代突飞猛进,本篇文章不免过期或有疏漏,请读者注意。
jvm
什么是CoroutineScope? CoroutineScope能够理解为协程的做用域
,能够管理其域内的全部协程。一个CoroutineScope能够有许多的子scope。async
建立子scope的方式有许多种,常见的有:ide
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R
这个api主要用于方便地建立一个子域,而且管理域中的全部子协程。注意这个方法只有在全部 block中建立的子协程所有执行完毕后,才会退出。以下示例:// print输出的结果顺序将会是 1, 2, 3, 4
coroutineScope {
delay(1000)
println("1")
launch {
delay(6000)
println("3")
}
println("2")
return@coroutineScope
}
println("4")
复制代码
与之相似的还有supervisorScope,区别是supervisorScope 在子协程失败时不影响其余子协程,而coroutineScope是将异常抛出。class SomethingWithLifecycle : CoroutineScope {
// 建立一个Job,并用这个job来管理你的SomethingWithLifecycle的全部子协程
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
// 当生命周期销毁时,结束全部子协程
fun close() { job.cancel() }
}
复制代码
这里我将CoroutineContext翻译为协程上下文。 我也找不到更好的词去翻译它。协程上下文包含当前协程scope的信息, 好比的Job, ContinuationInterceptor, CoroutineName 和CoroutineId。在CoroutineContext中,是用map来存这些信息的, map的键是这些类的伴生对象,值是这些类的一个实例。 这个设计也是蛮骚的, 致使你能够这样子取得context的信息:ui
val job = context[Job]
val continuationInterceptor = context[ContinuationInterceptor]
复制代码
每个信息(Element)的继承关系大概是这样的, 我拿Job来举例:spa
Job.Key继承了CoroutineContext.Key, Job 继承了CoroutineContext.Element,而CoroutineContext.Element继承了 CoroutineContext。.net
name 和 id都可有可无,咱们仔细讲讲Job和ContinuationInterceptor。
如上文提到的,Job继承了CoroutineContext.Element, 他是协程上下文的一部分。 Job有两个重要的子类实现:JobSupport,提供Job 的父子关系管理, 和AbstractCoroutine,即协程。
Job对象持有全部的子job实例,能够取消全部子job的运行。Job的join方法会等待本身以及全部子job的执行, 因此Job给予了CoroutineScope一个管理本身全部子协程的能力。
JobSupport这边的api已经被标记为废弃了,未来可能会有变更。其实这边api设计我感受有点看不懂,十分地confusing。之后看看有没有变化吧,这部分主要是提供一个 工厂方法 Job()
,能够为你的组件提供一个初始的context, 一个JobImpl的实例。JobSupport同时是AbstractCoroutine的父类。
讲讲Job最重要的子类: AbstractCoroutine。这个类就能够直接理解为是一个协程对象了,他继承了CoroutineScope, Job, Continuation, JobSupport。
常见地, 使用launch 或者async方法都会实例化出一个AbstractCoroutine 的协程对象,而这个协程对象由于继承了CoroutineScope,因此拥有一个协程上下文。 一个协程的协程上下文的Job值就是他自己,即:
val j = launch { delay(6000) }
// True!
println(j[Job] == j)
复制代码
而关于Continuation,是kotlin内部用来跳转恢复协程用的。这个东西对外部暴露的东西很少,咱们须要了解的有:
这个接口主要是由各类dispather实现。 见官方文档 肚子好饿,不详细介绍了,后面特别补上一篇文章细说dispatcher在各个平台的表现吧, 敬请期待。
最后推荐个神仙仓库吧, kotlin的各类提案, 在这里面能够看到各类kotlin特性设计的方案。好比协程的:
若是以为本篇文章对您有所帮助, 点个赞吧~~蟹蟹~