在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")
}
为什么在第一个示例中没有捕获异常?
答案 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文档中详细了解协程异常处理。