I’ve been playing around with coroutines for a little, and most of it seems smooth except for this particular case where Caught Exceptions are still propagated to the uncaughtExceptionHandler, which obviously makes the process crash.
The crashing code looks as following:
class MainActivity : AppCompatActivity(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab.setOnClickListener {
launch {
try {
async {
delay(1000)
throw IllegalStateException("This is my exception")
}.await()
} catch (e: IllegalStateException) {
Log.e("$this@MainActivity", "It is caught! $e ")
}
}
}
}
Note that there is an async
inside of a launch
and both of them are part of the same scope, and share the same context.
I am throwing the exception inside of the async
, and I subscribe immediately via await()
.
Now, the log of running this piece of code in Android is as follows:
com.efren.myapplication E/StandaloneCoroutine{Cancelling}@8ef5efd@MainActivity: It is caught! java.lang.IllegalStateException: This is my exception
Process: com.efren.myapplication, PID: 31097
java.lang.IllegalStateException: This is my exception
at com.efren.myapplication.MainActivity$onCreate$1$1$1.invokeSuspend(MainActivity.kt:37)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.ResumeModeKt.resumeMode(ResumeMode.kt:67)
at kotlinx.coroutines.DispatchedKt.resume(Dispatched.kt:272)
at kotlinx.coroutines.DispatchedKt.dispatch(Dispatched.kt:261)
at kotlinx.coroutines.AbstractContinuation.dispatchResume(AbstractContinuation.kt:182)
at kotlinx.coroutines.AbstractContinuation.completeStateUpdate(AbstractContinuation.kt:250)
at kotlinx.coroutines.AbstractContinuation.updateStateToFinal(AbstractContinuation.kt:222)
at kotlinx.coroutines.AbstractContinuation.resumeImpl(AbstractContinuation.kt:195)
at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuation.kt:262)
at kotlinx.coroutines.android.HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1.run(Runnable.kt:19)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6592)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
According to my tests, this can fixed by:
- Replace
async
+await()
for awithContext()
- Use a different
CoroutineScope
Although I am new to coroutines, this seems like it is either a bug, or I am missing something in the explanation of how all the elements work combined when handling exceptions.
Could somebody shed some light into what’s happening here? Since I am trying to move an entire project to coroutines, it’d be much appreciated.