前言
要写的内容在前面的文章都写的差不多了,这个最后研究一下一个比较重要的方法
suspendCoroutineUninterceptedOrReturn。suspendCoroutineUninterceptedOrReturn 因为其不凡的特性,使得它的地位极高,是一个很有存在感的函数。对于整个协程来说意义重大,花时间去了解它是非常值得的一件事情。
那么关于协程我们需要学习的东西还有很多,希望我们能够一起学习一同进步!
在协程提供的一些方法类似withContext ,delay ,join,suspendCoroutine,suspendCancellableCoroutine 等等内部都是通过suspendCoroutineUninterceptedOrReturn 实现的。我们这里以
一、suspendCoroutine
suspend fun testSuspendMethod() {
var outcome= suspendCoroutine<String> {
GlobalScope.launch {
println("我是GlobalScope.launc")
it.resumeWith(Result.success("我是返回值"))
}
println("我是suspendCoroutine")
}
//outcome 此时就是 字符串 “我是返回值”
println("我是testSuspendMethod")
}
打印顺序一般是"我是suspendCoroutine",“我是GlobalScope.launc”,(“我是testSuspendMethod” 这里说一般第一与第二输出可能会因为线程的调度导致顺序的不确定,比如在 1 处 线程可能会挂起然后调度GlobalScope.launch创建的协程所在的线程。
但是有一点是确定的 println(“我是GlobalScope.launc”) 一定是在 println(“我是testSuspendMethod”)之前执行。
我们进入源码看看
public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
//创建一个协程续体
val safe = SafeContinuation(c.intercepted())
//执行block,此处我们通过GlobalScope.launch 创建了一个新的协程
block(safe)
//由于线程调度的问题,此时GlobalScope.launch 创建的协程可能已经执行完了,在新的协程内部我们调用了
// it.resumeWith(Result.success("我是返回值")) it此处就是saft,那么此时getOrThrow 返回值就是
//字符串"我是返回值"
//加入此时新的协程还没有执行完,此时getOrThrow 返回值就是COROUTINE_SUSPENDED,表示当前协程挂起。
//然后等到 it.resumeWith(Result.success("我是返回值") 执行的时候会唤醒当前协程继续执行。
safe.getOrThrow()
}
上面解释的挺清楚的了,若是对具体细节还想做进一步了解的话,大家可以自己查看源码,在啰嗦一句,将编译好的class 文件反编译成java 可能更好理解。
public suspend inline fun <T> suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
throw NotImplementedError("Implementation of suspendCoroutineUninterceptedOrReturn is intrinsic")
suspendCoroutineUninterceptedOrReturn 的具体实现看不到,但是这里不妨碍我们的理解。
二、withContext
withContext(Dispatchers.IO){
println("我是suspendCoroutine")
}
public suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T = suspendCoroutineUninterceptedOrReturn sc@ { uCont ->
// compute new context
val oldContext = uCont.context
val newContext = oldContext + context
.............. 删除了一部分代码
// SLOW PATH -- use new dispatcher
val coroutine = DispatchedCoroutine(newContext, uCont) // MODE_ATOMIC_DEFAULT
coroutine.initParentJob()
//block会运行在一个新的线程里面,等block运行完成之后会调用coroutine.resumeWith
//把返回值传递过来,并唤醒协程
block.startCoroutineCancellable(coroutine, coroutine)
//这个更 safe.getOrThrow() 一样
coroutine.getResult()
}
这里删除了一部分代码,实际对于理解没有影响
val coroutine = DispatchedCoroutine(newContext, uCont) // MODE_ATOMIC_DEFAULT
coroutine.initParentJob()
//block会运行在一个新的线程里面,等block运行完成之后会调用coroutine.resumeWith
//把返回值传递过来,并唤醒协程
block.startCoroutineCancellable(coroutine, coroutine)
上面这三行代码很类似创建Global.launch 部分,大家感兴趣可以结合着协程创建那篇文章看看。