2.1.1 组合新的CoroutineContext
public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
val combined = coroutineContext + context
val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined
return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)
debug + Dispatchers.Default else debug
}
从上面可以提炼出以下信息:
1.会将launch
方法传入的context
与CoroutineScope
中的context
组合起来
2.如果combined
中没有拦截器,会传入一个默认的拦截器,即Dispatchers.Default
,这也解释了为什么我们没有传入拦截器时会有一个默认切换线程的效果
2.1.2 创建一个Continuation
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
默认情况下,我们会创建一个StandloneCoroutine
值得注意的是,这个coroutine
其实是我们协程体的complete
,即成功后的回调,而不是协程体本身
然后调用coroutine.start
,这表明协程开始启动了
2.2 协程的启动
public fun start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
initParentJob()
start(block, receiver, this)
}
接着调用CoroutineStart
的start
来启动协程,默认情况下调用的是CoroutineStart.Default
经过层层调用,最后到达了:
internal fun <R, T> (suspend ® -> T).startCoroutineCancellable(receiver: R, completion: Continuation) =
runSafely(completion) {
// 外面再包一层 Coroutine
createCoroutineUnintercepted(receiver, completion)
// 如果需要,做拦截处理
.intercepted()
// 调用 resumeWith 方法
.resumeCancellableWith(Result.success(Unit))
}
这里就是协程启动的核心代码,虽然比较短,却包括3个步骤:
1.创建协程体Continuation
2.创建拦截 Continuation
,即DispatchedContinuation
3.执行DispatchedContinuation.resumeWith
方法
2.3 创建协程体Continuation
调用createCoroutineUnintercepted
,会把我们的协程体即suspend block
转换成Continuation
,它是SuspendLambda
,继承自ContinuationImpl
createCoroutineUnintercepted
方法在源码中找不到具体实现,不过如果你把协程体代码反编译后就可以看到真正的实现
详情可见:字节码反编译
2.4 创建DispatchedContinuation
public actual fun Cont