返回

协程启动:揭秘Kotlin协程SafeCoroutine实现原理

Android

在深入理解Kotlin协程SafeCoroutine实现原理之前,我们先来回顾一下协程的基础知识。协程是一种轻量级的线程,它可以暂停并恢复执行。在Kotlin中,协程使用suspend来标记挂起函数,挂起函数可以在任何地方暂停执行,而不会阻塞线程。

SafeCoroutine的作用主要体现在以下两个方面:

  • 确保挂起点(continuation)的生命周期与CoroutineJob的生命周期绑定。
    这意味着,如果CoroutineJob被取消,那么挂起点也会被取消。这样可以避免在协程被取消后,继续执行挂起函数,从而导致错误。
  • 在取消的情况下清理continuation。
    这意味着,当协程被取消时,SafeCoroutine会调用continuation.resumeWith(CancellationException())来通知挂起函数已被取消。这样可以确保挂起函数在被取消后不会继续执行。

现在,我们来深入探讨一下SafeCoroutine的实现原理。SafeCoroutine是一个私有的内部类,它在suspendCoroutine函数中创建。suspendCoroutine函数的签名如下:

suspend fun <T> suspendCoroutine(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T

suspendCoroutine函数的作用是创建一个新的协程,并在协程中执行block函数。block函数是一个挂起函数,它可以暂停协程的执行。当block函数挂起时,suspendCoroutine函数会返回一个Continuation对象。这个Continuation对象代表了挂起点的状态,它可以用来恢复协程的执行。

SafeCoroutine在suspendCoroutine函数中创建,它继承自ContinuationImpl类。ContinuationImpl类是Continuation接口的默认实现。SafeCoroutine类重写了ContinuationImpl类的resumeWith()方法,以便在取消的情况下清理continuation。

override fun resumeWith(result: Result<T>) {
    val job = job ?: return // job == null means that resume was already invoked
    job.removeOnCancelListener(this) // we don't need it anymore
    if (result.isFailure) {
        resumeCancelled() // ensure that result.exception gets propagated
    } else {
        super.resumeWith(result)
    }
}

当SafeCoroutine的resumeWith()方法被调用时,它会先检查CoroutineJob是否为null。如果CoroutineJob为null,这意味着resume()方法已经被调用过,那么直接返回即可。否则,它会将CoroutineJob从SafeCoroutine中移除,因为SafeCoroutine不再需要CoroutineJob了。然后,它会检查result是否表示失败。如果result表示失败,它会调用resumeCancelled()方法来通知挂起函数已被取消。否则,它会调用父类的resumeWith()方法来恢复挂起函数的执行。

这就是SafeCoroutine的实现原理。它通过重写ContinuationImpl类的resumeWith()方法,来确保挂起点(continuation)的生命周期与CoroutineJob的生命周期绑定,以及在取消的情况下清理continuation。