Kotlin协程介绍(二)实现原理 中介绍过,挂起函数经过编译后以CPS的形式运行。反之,也可以将CPS转成挂起函数,使之可在协程中使用。这具体是通过suspendCoroutine{}或suspendCancellableCoroutine{}实现的
public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c.intercepted())
block(safe)
safe.getOrThrow()
}
public suspend inline fun <T> suspendCancellableCoroutine(
crossinline block: (CancellableContinuation<T>) -> Unit): T =
suspendCoroutineUninterceptedOrReturn { uCont ->
val cancellable = CancellableContinuationImpl(uCont.intercepted(), resumeMode = MODE_CANCELLABLE)
// 和 suspendCoroutine 的区别就在这里,如果协程已经被取消或者已完成,就会抛出 CancellationException 异常
cancellable.initCancellability()
block(cancellable)
cancellable.getResult()
}
suspendCoroutine和suspendCancellableCoroutine内部都会调用suspendCoroutineUninterceptedOrReturn,它会返回CPS的Continuation,通过Continuation回调结果或异常。
例如,我们可以将Guava的FutureCallback改造为挂起函数:
suspend fun <T> Future<T>.await(): T = suspendCoroutine {
Futures.addCallback(this, object: FutureCallback<T> {
override fun onSuccess(result: T?) {
if (result != null) {
it.resumeWith(Result.success(result))
}
}
override fun onFailure(t: Throwable) {
it.resumeWithException(t)
}
})
}
resumeWith传递执行结果,resumeWithExeption传递异常。