GlobalScope 在 Dispatchers.Main launch 的过程
GlobalScope.launch(Dispatchers.Main) {
println("hello word")
}
Log.e(TAG, "-----------------------")
--- source code ---
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
}
从这张流程图中,可以大概熟悉一下,一个简单的协程的的使用过程。
可以了解到:协程体怎么分发到对应的线程中执行:
这里的CoroutineDispatcher 就是 HandlerDispatch,在Dispatchers.Main执行的都是 通过Handler.post() 执行.
这里特别需要注意,supped.R() -> T 是 SuspendLambda 的子类. 由虚拟机生成,同时复写 invokeSuspend、create 和 invoke 方法
withContext 切换线程
GlobalScope.launch(Dispatchers.Main) {
Log.e(TAG, "run in main thread 1")
withContext(Dispatchers.IO) {
Log.e(TAG, "run in io thread")
}
Log.e(TAG, "run in main thread 2")
}
Log.e(TAG, "-----------------------")
看代码,会发现线程变化是: Main Thread -> IO Thread -> Main Thread
怎么做到的呢?
在Android中代码先执行到:GlobalScope.launch(Dispatchers.Main),会通过post,执行launch的代码体。
然后改变 Context,设置不同的Dispatchers,将 Log.e(TAG, "run in io thread")
分发到CommonPool 里面执行。
特别需要注意的是:有三个不同的路径来执行
-
context与父级的context相等
-
Dispatchers 与父级的Dispatchers相等
-
如果是新的Dispatchers,这里会构建DispatchedCoroutine,这个类会持有两个context,一个新的一个是旧的。
为的就是将线程切换过来(会在afterResume调用)
SuspendLambda 继承结构
状态机
https://kotlinlang.org/spec/asynchronous-programming-with-coroutines.html#coroutine-state-machine
// Lambda body with multiple suspension points
val a = a()
val y = foo(a).await() // suspension point #1
b()
val z = bar(a, y).await() // suspension point #2
c(z)
// State machine code for the lambda after CPS transformation
// (written in pseudo-Kotlin with gotos)
class <anonymous> private constructor(
completion: Continuation<Any?>
): SuspendLambda<...>(completion) {
// The current state of the state machine
var label = 0
// local variables of the coroutine
var a: A? = null
var y: Y? = null
fun invokeSuspend(result: Any?): Any? {
// state jump table
if (label == 0) goto L0
if (label == 1) goto L1
if (label == 2) goto L2
else throw IllegalStateException()
L0:
// result is expected to be `null` at this invocation
a = a()
label = 1
// 'this' is passed as a continuation
result = foo(a).await(this)
// return if await had suspended execution
if (result == COROUTINE_SUSPENDED)
return COROUTINE_SUSPENDED
L1:
// error handling
result.throwOnFailure()
// external code has resumed this coroutine
// passing the result of .await()
y = (Y) result
b()
label = 2
// 'this' is passed as a continuation
result = bar(a, y).await(this)
// return if await had suspended execution
if (result == COROUTINE_SUSPENDED)
return COROUTINE_SUSPENDED
L2:
// error handling
result.throwOnFailure()
// external code has resumed this coroutine
// passing the result of .await()
Z z = (Z) result
c(z)
label = -1 // No more steps are allowed
return Unit
}
fun create(completion: Continuation<Any?>): Continuation<Any?> {
<anonymous>(completion)
}
fun invoke(completion: Continuation<Any?>): Any? {
create(completion).invokeSuspend(Unit)
}
}
总结
supped.R() -> T 是 SuspendLambda 的子类. 由虚拟机生成,同时复写 invokeSuspend、create 和 invoke 方法
invokeSuspend 是一个状态机的构造,每个挂起点都是一个状态.
withContext 切换线程:在开启新的线程的时候,会将旧的context的封装到:DispatchedCoroutine(newContext, uCont),在afterResume的时候重启.