在协程中冒泡异常

时间:2019-05-29 19:11:38

标签: kotlin kotlin-coroutines

在Kotlin协程中,只有在检索到值之前,才会引发async调用。但是,当我在async块中启动暂停功能时,异常并未被捕获。

这是示例代码:

fun start() {
    GlobalScope.launch {
        try {
            val def1 = async { doWork1() }
            val def2 = async { doWork2() }
            Log.d("test", "Result ${def1.await()}, ${def2.await()}")
        } catch (ex: Exception) {
            Log.e("test", "Error", ex)
        }
    }
}

private suspend fun doWork1(): Int {
    delay(1000L)
    throw Exception("work 1")
}

private suspend fun doWork2(): Int {
    delay(1000L)
    return 1
}

这会崩溃,而不是将异常捕获在catch块中。

另一方面,这很好

fun start() {
    GlobalScope.launch {
        try {
            val value = doWork1()
            Log.d("test", "Result: $value")
        } catch (ex: Exception) {
            Log.e("test", "Error", ex)
        }
    }
}

private suspend fun doWork1(): Int {
    delay(1000L)
    throw Exception("work 1")
}

为什么在第一个示例中没有捕获异常?

1 个答案:

答案 0 :(得分:1)

第二种情况很简单:您只用job运行1个GlobalScope.launch,而exception被完全捕获了。

但是,在第一种情况下,您的async调用会创建属于GlobalScope.launch的子任务的工作。

异常实际上被延迟到await()调用为止,但是在这种情况下不会重新抛出。相反,async作业将异常传播到其父作业(launch),该作业继续取消自身和所有子作业。它将异常转发到其ExceptionHandler,默认情况下该异常未被捕获。

您应该在父作业上下文中安装异常处理程序-这样可以对协程或其子级中的任何异常进行干净的处理:

GlobalScope.launch(CoroutineExceptionHandler { coroutineContext, throwable ->
        println("Error: $throwable")
}) {
    val def1 = async { doWork1() }
    val def2 = async { doWork2() }
    println("Result ${def1.await()} ${def2.await()}") 
}

Exception Handling文档中详细了解协程异常处理。