持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
协程的异常处理
当应用出现一些意外情况时,给用户提供合适的体验非常重要,一方面应用崩溃是个糟糕的体验,另一方面在用户操作失败时,也必须给出正确的提示信息。
异常的传播
协程构建器有两种形式
- 自动传播异常(launch和actor)异常会在它发生的第一时间被抛出
- 向用户暴露异常(async和produce)依赖用户来最终消费异常。
当一个协程由于异常而运行失败时,它会传播这个异常并传递给它的父级,而它的父级会进行以下几个操作
- 取消它自己的子级
- 取消它自己
- 将异常传播并传递给它的父级
SupervisorJob
使用SupervisorJob时,一个子协程的运行失败不会影响到其他子协程。SupervisorJob不会传播异常给它的父级,它会让子协程自己处理异常。
使用场景:
任何一个UI的子作业执行失败,它并并总是有必要取消整个UI组件
supervisorScope
当作业自身执行失败时,取消所有子作业
异常的捕获
使用CoroutineExceptionHandler进行协程的异常捕获
当满足以下条件时,异常就会被捕获
- 时机: 异常是被自动抛出异常的协程所抛出的(使用launch,而不是async时)
- 位置: 在CoroutineScope的CoroutineContext或在一个根协程(CoroutineScope或者supervisorScope的直接子协程)中
Android中全局异常处理
全局异常处理器可以捕获到所有协程未处理的未捕获的异常,不过它并不能对异常进行捕获,虽然不能阻止程序崩溃,但是全局异常处理器在程序调试和异常上报等场景中仍然有非常大的用处。
新建全局异常处理器的步骤:
- 首先我们需要在classpath下面创建META-INF/services目录
- 其次在services目录中创建一个kotlinx.coroutines.CoroutineExceptionHandler文件,文件内容就是我们的全局异常处理器的全类名
取消和异常
- 取消和异常紧密相关,协程内部使用CancellationException来进行取消,这个异常会被忽略
- 当子协程被取消时,不会取消它的父协程
- 如果一个协程遇到来cancellationException以为的异常,它将使用该异常取消它的父协程。
- 当父协程的所有子协程都结束后,异常才会被父协程处理
异常聚合
当协程的多个子协程因为异常而失败时,一般情况取第一个异常进行处理。在第一个异常之后发生的所有其他异常都将绑定到第一个异常上