避免在子协程异常时取消父工作

Gau*_*han 3 kotlin kotlinx.coroutines

我正在尝试在Android的Kotlin协程中处理异常

我的用例是我想在后台执行一系列任务(以异步方式),并在单个活动中更新多个UI组件。

我设计了一个BaseActivity要实现的结构,CoroutineScope以便可以将调用的Couroutine与活动的生命周期结合在一起。

另外,我有一个Repository处理网络调用的类。

我已经实现了同时运行多个任务。我知道如果我使用单个Job对象取消活动中的所有协程并onDestroy()在活动中执行(launch)多个协程,则任何单个协程中的Exception都会Job从其中取消CoroutineContext。并且由于Job附加到活动的生命周期中,它也会取消所有其他协程。

我尝试使用CoroutineExceptionHandler。它捕获异常,但也取消Job。结果取消了所有其他协程。

我想要的是?

  1. 能够使用单个 Job对象附加活动生命周期
  2. 一个协程中的异常不应取消其他协程

在下面添加代码

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")
}
}
Run Code Online (Sandbox Code Playgroud)

的日志结果是

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
Run Code Online (Sandbox Code Playgroud)

Paw*_*wel 5

您可能要取代你JobSupervisorJob

它可以防止异常传播到“向上”(一个失败的孩子不会导致整个工作失败),但是仍然可以让您将取消“向下”(向正在运行的孩子)推送。