我正在将一些旧的RxJava代码移植到协程。使用RxJava,我可以在自己的 Activity 中执行此操作:
someBgOperation()
.as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(MyActivity.this)))
.subscribe(
MyActivity.this::onSuccess,
MyActivity.this::onError
);
如果 Activity 被关闭,则自动处置库将取消Observable。在这种情况下,RxJava不会调用错误处理程序,因此可以安全地在错误处理程序中执行与UI相关的操作,例如显示对话框。
现在,在Kotlin中,我们可以从Activity中的
lifecycleScope
或如果使用ViewModel的viewModelScope
中启动以下等效代码:viewModelScope.launch {
try {
someBgOperation()
} catch (e: Exception){
//show dialog
}
}
Activity 关闭时,这两个作用域都会自动取消,这与Autodispose一样。但是catch块不仅会通过
someBgOperation
本身抛出的正常错误执行,还会通过协程库在幕后使用的CancellationException
来执行取消操作。如果在 Activity 关闭时尝试在其中显示对话框,则可能会出现新的异常。所以我被迫做这样的事情:viewModelScope.launch {
try {
someBgOperation()
} catch (ce: CancellationException){
//do nothing, activity is closing
} catch (e: Exception){
//show dialog
}
}
这比Rx版本更冗长,并且具有空的catch子句,该子句会在lint输出中显示警告。在其他情况下,在 try catch 后执行更多操作时,我被迫从
CancellationException
捕获返回以保持UI安全(这些返回被标记为返回)。我发现自己一次又一次地重复这个丑陋的模板。有没有更好的方法来忽略CancellationException?
最佳答案
我可以提出两种解决方案。首先,附加的catch(e: CancellationException)
子句看起来有些冗长。您可以将代码简化为:
viewModelScope.launch {
try {
someBgOperation()
} catch (e: Exception) {
if (e !is CancellationException) // show dialog
}
}
另一方面,您可以使用Kotlin Flow,其Kotlin Flow的
catch
运算符旨在完全忽略此取消。由于实际上您将不会在该流上发送任何值,因此您应该使用Flow<Nothing>
:flow<Nothing> {
someBgOperation()
}.catch { e ->
// show dialog
}.launchIn(viewModelScope)
关于android - Kotlin:如何绕过CancellationException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62220286/