kotlin实现恢复挂起点是通过一个接口类Continuation(英文翻译过来叫"继续、延续、续体")来实现的。
Kotlin 续体有两个接口: Continuation
和 CancellableContinuation, 顾名思义 CancellableContinuation 是一个可以取消的 Continuation。
public interface Continuation<in T> {
public val context: CoroutineContext
public fun resumeWith(result: Result<T>)
}
Continuation 的成员:
-
val context: CoroutineContext: 当前协程的 CoroutineContext 上下文
-
fun resumeWith(result: Result<T>): 传递 result 恢复协程
CancellableContinuation 成员:
-
isActive, isCompleted, isCancelled: 表示当前 Continuation 的状态
-
fun cancel(cause: Throwable? = null): 可选通过一个异常 cause 来取消当前 Continuation 的执行
可以将 Continuation 看成是在挂起点恢复后需要执行的代码封装(状态机实现),比如说对如下逻辑:
suspend fun request() = suspendCoroutine<Response> {
val response = doRequest()
it.resume(response)
}
fun test() = runBlocking {
val response = request()
handle(response)
}
用下面的伪代码简单描述 Continuation 的工作:
interface Continuation<T> {
fun resume(t: T)
}
fun request(continuation: Continuation<Response>) {
val response = doRequest()
continuation.resume(response)
}
fun test() {
request(object :Continuation<Response>{
override fun resume(response: Response) {
handle(response)
}
})
}
对于 suspend 关键词修饰的挂起函数,编译器会为其增加一个 Continuation 续体类型的参数(相当于 CPS 中的回调),可以通过这个 Continuation 续体对象的 resume 方法返回结果值来恢复协程的执行。
协程的创建
在kotlin当中创建一个简单协程不是什么难事

标准库中提供了一个
createCoroutinue 函数,我们可以通过它来创建协程,不过这个协程并不会立即执行。
我们先来看看它的声明:
fun <T> (suspend () -> T).createCoroutine(completion: Continuation<T>): Continuation<Unit>
其中
suspend () -> T 是
createCoroutinue 函数的
Receiver
-
Receiver 是一个被 suspend 修饰的挂起函数,这也是协程的执行体,我们不妨称它为 协程体。
-
参数 completion 会在协程执行完成后调用,实际上就是协程的 完成回调。
-
返回值是一个 Continuation 对象,由于现在协程仅仅被创建处理,因此需要通过这个值在之后触发协程的启动。
协程的启动
我们已经知道如何创建协程,那么协程要如何运行呢?调用
continuation.resume(Unit) 之后,协程体会立即开始执行。
通过阅读
createCoroutine 的源码或者直接打断点调试,我们可以得知
continuation 是
SafeContinuation