Kotlin协程源码分析-6 suspendCoroutineUninterceptedOrReturn注意点
学完状态机之后来看看他可以帮我们理解什么。我们回头看看suspendCoroutineUninterceptedOrReturn获取挂起函数的注意点:1.不要轻易在同一个调用挂起函数的栈帧中调回Continuation.resumeWithException或者Continuation.resume2. 如果不是立即返回结果,请务必返回kotlin.coroutines.intrinsics...
学完状态机之后来看看他可以帮我们理解什么。
我们回头看看suspendCoroutineUninterceptedOrReturn获取挂起函数的注意点:
1.不要轻易在同一个调用挂起函数的栈帧中调回Continuation.resumeWithException或者Continuation.resume
2. 如果不是立即返回结果,请务必返回kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
看一个例子
//com.example.studycoroutine.chapter.two.MyCoroutine.kt
class MyCoroutine() : Continuation<String> {
override fun resumeWith(result: Result<String>) {
logD("MyCoroutine 回调resumeWith 返回的结果 " + result.getOrNull())
}
override val context: CoroutineContext
get() = kotlin.coroutines.EmptyCoroutineContext
}
/**
*
*/
suspend fun firstSuspend() = suspendCoroutineUninterceptedOrReturn<String> { continuation ->
continuation.resume("hello ")
logD("虽然协程返回了结果,但是我依然要打印")
kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
}
fun defaultResumeIo() {
val lambda = suspend {
val firstSuspend = firstSuspend()
logD("返回的结果是" + firstSuspend)
firstSuspend
}
val myCoroutine = MyCoroutine()
lambda.startCoroutine(myCoroutine)
}
输出:
[main] 返回的结果是hello
[main] MyCoroutine 回调resumeWith 返回的结果 hello
[main] 虽然协程返回了结果,但是我依然要打印
这很显然存在一个逻辑问题,重复进入状态机两次,第一次进入正常启动进入,第二次continuation.resume("hello ")调用后立即进入BaseContinuationImpl的resumeWith函数,然后显示的完成结果于是回调MyCoroutine。然后firstSuspend却没结束,接着打印一个log。然后返回kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED,此时BaseContinuationImpl判断结果是挂起标识,于是返回。虽然上述代码不会奔溃,但是很容易出现意向不到的问题。
来模拟一个奔溃吧
suspend fun firstSuspend() = suspendCoroutineUninterceptedOrReturn<String> { continuation ->
continuation.resume("hello ")
logD("虽然协程返回了结果,但是我依然要打印")
// kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
"你好返回"
}
fun defaultResumeIo() {
val lambda = suspend {
val firstSuspend = firstSuspend()
logD("返回的结果是" + firstSuspend)
firstSuspend
}
val myCoroutine = MyCoroutine()
lambda.startCoroutine(myCoroutine)
}
输出:
2020-03-27 21:51:52.746 10797-10797/com.example.studycoroutine E/LOG: [main] 返回的结果是hello
2020-03-27 21:51:52.746 10797-10797/com.example.studycoroutine E/LOG: [main] MyCoroutine 回调resumeWith 返回的结果 hello
2020-03-27 21:51:52.746 10797-10797/com.example.studycoroutine E/LOG: [main] 虽然协程返回了结果,但是我依然要打印
2020-03-27 21:51:52.746 10797-10797/com.example.studycoroutine E/LOG: [main] 返回的结果是你好返回
2020-03-27 21:51:52.747 10797-10797/com.example.studycoroutine D/AndroidRuntime: Shutting down VM
2020-03-27 21:51:52.747 10797-10797/com.example.studycoroutine E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.studycoroutine, PID: 10797
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.studycoroutine/com.example.studycoroutine.MainActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Caused by: kotlin.KotlinNullPointerException
at kotlin.coroutines.jvm.internal.ContinuationImpl.releaseIntercepted(ContinuationImpl.kt:118)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:39)
at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:114)
at com.example.studycoroutine.chapter.seven.InterceptDemoKt.defaultResumeIo(InterceptDemo.kt:31)
at com.example.studycoroutine.MainActivity.onCreate(MainActivity.kt:17)
at android.app.Activity.performCreate(Activity.java:6662)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
这回输出异常,还奔溃了。
MyCoroutine回调两次,最后引起空指针。
回调两次MyCoroutine是由于suspendCoroutineUninterceptedOrReturn最后返回的不为挂起函数的标识,导致BaseContinuationImpl重复判断。至于空指针就不用多说了大家学习拦截器的时候再看看 ,这里是由于调用releaseIntercepted内部释放资源导致
更多推荐



所有评论(0)