我正在尝试使用 在 Android 上的 Kotlin 协程中处理异常。
我的用例是我想在后台(以异步方式)执行一堆任务并在单个事件上更新多个 UI 组件。
我设计了一个 BaseActivity
结构来实现 CoroutineScope
,这样我就可以将调用的 couroutines 与事件的生命周期结合起来。
另外,我有一个处理网络调用的 Repository
类。
我已经实现了同时运行多个任务。我知道如果我使用单个 Job
对象来取消事件的 onDestroy()
上的所有协程并在事件中执行( launch
)多个协程,则任何单个协程中的异常都会从其 Job
中取消 CoroutineContext
。由于 Job
附加到事件的生命周期,它也会取消所有其他协程。
我试过使用 CoroutineExceptionHandler
。它捕获异常但也取消了 Job
。结果取消了所有其他协程。
我想要的是?
Job
对象来附加事件生命周期 在下面添加代码
class BaseActivity : AppCompatActivity(), CoroutineScope {
val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
launch(coroutineContext) {
Log.i("GURU", "launch1 -> start")
val result1Deferred = async { Repository().getData(1) }
val result2Deferred = async { Repository().getData(2) }
Log.i("GURU", "awaited result1 = " + result1Deferred.await() + result2Deferred.await())
}
//If Exception is Thrown, Launch1 should still continue to complete
advancedLaunch(coroutineContext) {
Log.i("GURU", "launch2 -> start")
val result1Deferred = async { Repository().getData(3) }
val result2Deferred = async { Repository().getData(4) }
delay(200)
throw Exception("Exception from launch 2")
Log.i("GURU", "awaited result2 = " + result1Deferred.await() + result2Deferred.await())
}
}
fun CoroutineScope.advancedLaunch(context: CoroutineContext = EmptyCoroutineContext,
exceptionBlock: (Throwable) -> Unit = {Log.i("GURU", it.message)},
launchBlock: suspend CoroutineScope.() -> Unit) {
val exceptionHandler = CoroutineExceptionHandler { _, throwable -> exceptionBlock(throwable)}
launch(context + exceptionHandler) { launchBlock() }
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
Log.i("GURU", "job -> cancelled")
}
}
这个的日志结果是
I/GURU: launch1 -> start
I/GURU: launch2 -> start
I/GURU: getData -> start 1
I/GURU: getData -> start 2
I/GURU: getData -> start 4
I/GURU: getData -> start 3
I/GURU: Exception from launch 2
--------- beginning of crash
最佳答案
您可能想用 Job
替换 SupervisorJob
。
它可以防止异常“向上”传播(一个失败的子项不会导致整个作业失败),但仍然允许您“向下”(向正在运行的子项)推送取消。
关于kotlin - 避免在子协程异常时取消父作业,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53132989/