1.3.5 Kotlin协程

Kotlin协程(Coroutines)也是为异步程序设计而生的。有人称它只是一个“线程框架”,认为Kotlin协程就是用来切换线程的,这显然有些“一叶障目,不见泰山”了。

Kotlin协程的设计很巧妙,它只用了一个关键字suspend来表示挂起点,包含了异步调用和回调两层含义。我们前面提到,所有异步回调对于当前调用流程来讲都是一个挂起点,在这个挂起点我们可以做的事情非常多,既可以像async/await那样异步回调,又可以添加调度器来处理线程切换,还可以作为协程取消响应的位置,等等。

我们先来看一个Kotlin协程处理异步调用的例子,见代码清单1-23。

代码清单1-23 使用Kotlin协程


suspend fun bitmapSuspendable(url: String): Bitmap =
  suspendCoroutine<Bitmap> { continuation ->
    thread {
      try {
        continuation.resume(download(url))
      } catch (e: Exception) {
        continuation.resumeWithException(e)
      }
    }
  }

被suspend关键字修饰的函数叫作挂起函数(suspend function),类似我们前面提到的被async修饰的函数,表示该函数支持同步化的异步调用。

我们使用标准库API suspendCoroutine<T>函数的返回值类型作为挂起函数bitmap-Suspendable的返回值类型,也就是泛型参数T的实参Bitmap。这个函数除了确定返回值类型外,还能够帮我们拿到一个Continuation的实例,负责保存和恢复挂起状态,逻辑效果上类似于Promise,其中几个函数意义如下。

·resume:类似于Promise的resolve,将正常的结果返回,它的参数实际上就是bitmapSuspendable的返回值Bitmap。

·resumeWithException:类似于Promise的reject,将异常返回,它的参数实际上就是bitmapSuspendable调用时会抛出的异常。

调用时,所有的挂起函数必须在其他挂起函数(或者协程体)中调用,这就好像await只能在async当中使用一样,如代码清单1-24所示。

代码清单1-24 调用Kotlin的挂起函数


suspend fun main() {
  try {
    val bitmap = bitmapSuspendable("...")
    ... //省略图片处理
  } catch (e: Exception) {
    ...//省略异常处理
  }
}

调用时,挂起函数就相当于await之后的结果,因此大家可以看到,suspend这个关键字可以说是“分饰两角”:声明函数类型时充当async的作用,调用时充当await的作用。

这里我们仅仅对Kotlin协程进行简单介绍,目的是让大家充分了解异步程序设计的发展过程。我们将从第3章开始系统剖析Kotlin协程的实现细节和运用场景。

提示 Kotlin从1.3.0开始正式支持协程,suspend fun main作为入口函数也同时得到了支持。