原理篇(二)CoroutineScope.launch{} 过程分析
launch 的流程
先贴上 launch 的源码:
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
step 1 创建 CoroutineContext
执行的代码块如下:
val newContext = newCoroutineContext(context)
首先会,根据传入的 CoroutineContext,由于没有传入 CoroutineContext,则使用默认的EmptyCoroutineContext,作为参数值
//CoroutineScope.newCoroutineContext() 方法
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
}
在这个 newCoroutineContext() 方法里面,会将作为参数的 Context,也就是 EmptyCoroutineContext,和当前的 Coroutine,也就是 BlockingCoroutine,关联在一起。
接着会根据是否 Debug 模式,如果是 Debug 的话,会对协程设置协程ID,方便调试;具体 Debug 设置,可以参考 Debug.kt 中 DEBUG_PROPERTY_NAME,相关解释。
最后根据当前的 CoroutineContext 是否有 Dispatcher,并且没有 ContinuationInterceptor,如果都没有的话,则为该 CoroutineContext 关联 Dispatchers.Default。由于我们是没有设置的,所以进入该方法,会给当前的 CoroutineContext 关联一个 Dispatchers.Default。
step 2 创建 Coroutine
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
接着会根据 CoroutineStart 的模式,确认当前的 Coroutine 是 StandaloneCoroutine 还是 LazyStandaloneCoroutine。
至于两者的区别仅仅在于,Lazy 模式下:
-
构造参数 active = false,非 Lazy 默认是 true,这个值是传入作为 JobSupport 中作为构造函数,也是 Job 状态机里面的初始值变量,如下:
private val _state = atomic<Any?>(if (active) EMPTY_ACTIVE else EMPTY_NEW)
也就是说,如果是 Lazy 模式,则状态机进入的是 EMPTY_NEW 模式,非 Lazy 模式进入的是 EMPTY_ACTIVE 模式,这两个模式的可以简单认为,new 需要一种行为,让它进入 active。具体的解释,看Job-状态机 这一章节的分析
-
Lazy 模式下,会将代码块存进 bolck 参数里面,等待调用 start(),join(),await() 等,会执行 onStart() 回调,这会,代码块才会真正的执行。
具体看源码如下:
//Builder.Common.kt 文件下
private open class StandaloneCoroutine(
parentContext: CoroutineContext,
active: Boolean
) : AbstractCoroutine<Unit>(parentContext, active) {
override val cancelsParent: Boolean get() = true
override fun handleJobException(exception: Throwable) = handleExceptionViaHandler(parentContext, exception)
}
private class LazyStandaloneCoroutine(
parentContext: CoroutineContext,
block: suspend CoroutineScope.() -> Unit
) : StandaloneCoroutine(parentContext, active = false) {
private var block: (suspend CoroutineScope.() -> Unit)? = block
override fun onStart(