Kotlin 避免取消子协同程序异常时的父作业
我正在尝试在Android上的Kotlin协同程序中处理异常 我的用例是希望在后台(以异步方式)执行一系列任务,并在单个活动上更新多个UI组件 我设计了一个Kotlin 避免取消子协同程序异常时的父作业,kotlin,kotlinx.coroutines,Kotlin,Kotlinx.coroutines,我正在尝试在Android上的Kotlin协同程序中处理异常 我的用例是希望在后台(以异步方式)执行一系列任务,并在单个活动上更新多个UI组件 我设计了一个BaseActivity结构来实现CoroutineScope,这样我就可以将调用的例程与活动的生命周期耦合起来 此外,我还有一个存储库类,用于处理网络调用 我已经实现了同时运行多个任务。我知道如果我使用一个作业对象取消活动的onDestroy()上的所有协程,并在活动中执行(启动)多个协程,则任何单个协程中的异常都将从其协程文本中取消作业。
BaseActivity
结构来实现CoroutineScope
,这样我就可以将调用的例程与活动的生命周期耦合起来
此外,我还有一个存储库类,用于处理网络调用
我已经实现了同时运行多个任务。我知道如果我使用一个作业
对象取消活动的onDestroy()
上的所有协程,并在活动中执行(启动
)多个协程,则任何单个协程中的异常都将从其协程文本
中取消作业
。由于作业
附加到活动的生命周期,所以它也将取消所有其他协同程序
我尝试过使用一个CoroutineExceptionHandler
。它捕获异常,但也取消作业
。其结果是取消所有其他协同路由
我想要什么
能够使用单个作业
对象与活动生命周期连接
一个协程中的异常不应取消其他协程
在下面添加代码
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
您可能希望将作业
替换为
它防止异常“向上”传播(一个失败的子项不会导致整个作业失败),但仍然允许您“向下”推取消(到正在运行的子项)。您可能希望用替换作业。@Pawel谢谢。我在文档中错过了它。在正确的答案中加上这个,我会接受的