协程的创建

import kotlin.coroutines.*

val continuation = suspend {
    println("5")
    5
}.createCoroutine(object : Continuation<Int> {
    override val context: CoroutineContext
        get() = EmptyCoroutineContext

    override fun resumeWith(result: Result<Int>) {
        println("Coroutine End:$result")
    }
})
  • 标准库提供了一个createCoroutine函数,可通过它来创建协程,但这个协程并不会立即执行。
  • 标准库也提供了startCoroutine函数,可以创建协程后就立即让它开始执行。
//createCoroutine 函数声明
fun <T> (suspend () -> T).createCoroutine(
    completion: Continuation<T>
): Continuation<Unit>

//startCoroutine 函数声明
fun <T> (suspend () -> T).startCoroutine(  
    completion: Continuation<T>  
)
  • suspend () -> TcreateCoroutine 函数的Receiver,是协程的执行体 ,称为协程体
  • 参数completion在协程执行完后调用,是协程的完成回调
  • createCoroutine函数的返回值是一个Continuation本体|Continuation对象,startCoroutine函数的返回值是Unit。

协程的启动

  • 通过调用continuation.resume(Unit)之后,协程体会立即开始执行。
  • continuation.resumeWithException(Exception("Custom Exception"))

协程体的Receiver

fun <R, T> (suspend R.() -> T).createCoroutine(  
    receiver: R,  
    completion: Continuation<T>  
): Continuation<Unit>

fun <R, T> (suspend R.() -> T).startCoroutine(  
    receiver: R,  
    completion: Continuation<T>  
)
  • suspend R.() -> T多了一个Receiver类型R。R可以为协程体提供一个作用域,即可以在协程体中直接使用作用域内提供的函数或者状态等

  • ⬇️封装的launchCoroutine方法间接实现声明带有Receiver的Lambda表达式的语法。

fun <R, T> launchCoroutine(receiver: R, block: suspend R.() -> T) {  
    block.startCoroutine(receiver, object : Continuation<T> {  
        override fun resumeWith(result: Result<T>) {  
            println("Coroutine End:$result")  
        }  
  
        override val context: CoroutineContext  
            get() = EmptyCoroutineContext  
    })  
}
  • ⬇️例子
//1.创建一个模拟一个生成器协程的作用域
//@RestrictsSuspension 
class ProducerScope<T> {  
    suspend fun produce(value: T) {  
        delay(1000L)  
        println("value = $value")  
    }  
}  
  
fun callLaunchCoroutine() {  
    launchCoroutine(ProducerScope<Int>()) {  
     //2.添加了作用域ProducerScope作为Receiver,即可以直接调用ProducerScope的produce函数。
        println("In Coroutine")  
        produce(1024)//作用域的挂起函数
        delay(2000L)//外部挂起函数(若启用了@RestrictsSuspension注解,这句将会报错)
        produce(2048)  
    }  
}
  • @RestrictsSuspension注解的作用下,协程体就无法调用外部的挂起函数。

Continuation本体

  • continuation的类名类似于<FileName>Kt$<FunctionName>$continuation$1
    • <FileName> 指代的是代码所在的文件名
    • <FunctionName> 指代的是代码所在的函数名
  • Continuation本体是一个匿名内部类,编译器在编译后生成一个匿名内部类,这个类继承自SuspendLambda类,同时又是Continuation接口的实现类。