前言
我们需要了解到以下前置知识:
1.协程通过异常处理器来捕获异常
2.协程取消时会抛出CancellationException
,需要特别对待
3.协程中存在不同的作用域,不同作用域的异常传播机制不同
看到上面这些前置知识,本文主要内容也就呼之欲出了
1.协程异常处理器是如何生效的?
2.协程取消时的异常如何处理?
3.不同的作用域的异常传播机制不同是怎样实现的?
4.协程异常传播流程图总结
1. 前置知识
本文主要内容是对kotlin
协程异常传播的原理介绍,下面先介绍一下前置知识
1.1 异常处理器
kotlin
异常处理器即CoroutineExceptionHandler
,CoroutineExceptionHandler
也继承于CoroutineContext
在创建协程时添加到上下文中,在发生异常时通过key
从上下文中获得
我们一般这样使用:
val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
println("error")
}
viewModelScope.launch(handler) {
//...
}
1.2 协程作用域
协程作用域主要用于明确协程之间的父子关系,以及对于取消或者异常处理等方面的传播行为,主要分为以下三类:
- 顶级作用域:没有父协程的协程所在的作用域为顶级作用域
- 协同作用域:协程中启动新的协程,新协程为所在协程的子协程,这种情况下子协程所在的作用域默认为协同作用域。此时子协程抛出的未捕获异常都将传递给父协程处理,父协程同时也会被取消。
- 主从作用域:与协同作用域在协程的父子关系上一致,区别在于处于该作用域下的协程出现未捕获的异常时不会将异常向上传递给父协程
1.3 异常传播机制
协程最创新的功能之一就是结构化并发。为了使结构化并发的所有功能成为可能,CoroutineScope
的Job
对象以及Coroutines
和Child-Coroutines
的Job
对象形成了父子关系的层次结构。
未捕获的异常会优先向上传播,直到没有父协程才自行处理。这种异常传播会导致父Job
的失败,进而导致其子级所有Job
的取消。
如上所示,子协程的异常传播到协程(1)的Job
,然后传播到topLevelScope
(2)的Job
。
但是如果我们中间使用了supervisorScope
,它将截断异常向上传播
2. 异常处理器是如何生效的?
我们一般使用CoroutineExceptionHandler
来处理异常,简单示例如下
fun testExceptionHandler() {
val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
print("error")
}
viewModelScope.launch(handler) {
print("1")