I'm porting some old RxJava code to Coroutines. With RxJava I could do this in my activity:
someBgOperation()
.as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(MyActivity.this)))
.subscribe(
MyActivity.this::onSuccess,
MyActivity.this::onError
);
The autodispose library would cancel the Observable if the activity was being closed. In this case RxJava would not call the error handler, so it was possible to do UI-related operations in the error handler safely, such as showing a dialog.
Now in Kotlin we could have this equivalent code launched from lifecycleScope
in the Activity, or in a viewModelScope
if using ViewModel:
viewModelScope.launch {
try {
someBgOperation()
} catch (e: Exception){
//show dialog
}
}
Both scopes are automatically cancelled when the activity closes, just what Autodispose does. But the catch block will execute not only with normal errors thrown by someBgOperation
itself, but also with CancellationException
s that are used by the coroutines library under the hood to handle cancellation. If I try to show a dialog there while the activity is being closed, I might get new exceptions. So I'm forced to do something like this:
viewModelScope.launch {
try {
someBgOperation()
} catch (ce: CancellationException){
//do nothing, activity is closing
} catch (e: Exception){
//show dialog
}
}
This feels more verbose than the Rx version and it has an empty catch clause, which would show a warning in the lint output. In other cases where I do more things after the try-catch, I'm forced to return from the CancellationException
catch to stay UI-safe (and those returns are tagged returns). I'm finding myself repeating this ugly template again and again.
Is there a better way of ignoring the CancellationException?
if
's. If only a negative catch existed, like} catch (e: !CancellationException){
. – Cowey