kotlin: CoroutineExceptionHandler协程异常处理器
一,CoroutineExceptionHandler不同的用法
统一给父协程定义一个 CoroutineExceptionHandler,
如果一个子协程异常了,其他子协程也不需要继续的话就采用 coroutineScope 方法,默认的 Job 就是这种表现,
如果一个子协程异常了,其他子协程还需要继续的话就采用 supervisorScope 方法,
或者创建协程作用域的时候传入带 SupervisorJob() 函数返回的特殊 Job 的协程上下文
如果一个子协程异常了,其他子协程也不需要继续的话就采用 coroutineScope 方法,默认的 Job 就是这种表现,
如果一个子协程异常了,其他子协程还需要继续的话就采用 supervisorScope 方法,
或者创建协程作用域的时候传入带 SupervisorJob() 函数返回的特殊 Job 的协程上下文
二,例一:用supervisorScope启动协程
代码:
//处理按钮点击事件
binding.button1.setOnClickListener {
runBlocking {
//定义异常处理
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
//CoroutineExceptionHandler#handleException 方法回调
println("这里是exceptionHandler:协程:"+"${coroutineContext[CoroutineName].toString()} 捕捉到异常 :$throwable")
}
launch(exceptionHandler) { //传递给父协程
supervisorScope {
launch(CoroutineName("异常子协程")) {
println("${Thread.currentThread().name}:"+"我要开始抛异常了")
throw NullPointerException("空指针异常")
}
for (index in 0..10) {
launch(CoroutineName("子协程$index")) {
if (index %3 == 0){
println("${Thread.currentThread().name}:"+"$index 将抛出异常")
throw NullPointerException("子协程${index}空指针异常")
} else {
println("${Thread.currentThread().name}正常执行:"+"$index")
}
}
}
}
}
}
}
运行结果:

三,例二,CoroutineScope(SupervisorJob() + exceptionHandler) 方式启动协程
代码:
//处理按钮点击事件
binding.button2.setOnClickListener {
runBlocking {
//定义CoroutineExceptionHandler
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
//CoroutineExceptionHandler#handleException 方法回调
println("exceptionHandler:协程:"+"${coroutineContext[CoroutineName].toString()} 捕捉到异常 :$throwable")
}
//CoroutineScope 方法,
//SupervisorJob 方法代表子协程会自己处理异常,并不会影响其兄弟协程或者父协程
val supervisorScope = CoroutineScope(SupervisorJob() + exceptionHandler)
with(supervisorScope) {
launch(CoroutineName("异常子协程")) {
println("${Thread.currentThread().name}:"+"我要开始抛异常了")
throw NullPointerException("空指针异常")
}
for (index in 0..10) {
launch(CoroutineName("子协程$index")) {
if (index % 3 == 0) {
println("${Thread.currentThread().name}:"+"$index 将抛出异常")
throw NullPointerException("子协程${index}空指针异常")
} else {
println("${Thread.currentThread().name}正常执行:"+"$index")
}
}
}
}
}
}
运行结果:

四,例三,使用CoroutineScope时,一个子协程异常后其他子协程也不会继续
代码:
//处理按钮点击事件
binding.button3.setOnClickListener {
runBlocking {
//定义异常处理器
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
//CoroutineExceptionHandler#handleException 方法回调
println("exceptionHandler:协程:"+"${coroutineContext[CoroutineName].toString()} 捕捉到异常 :$throwable")
}
//CoroutineScope 方法,不再采用SupervisorJob
val scope = CoroutineScope(exceptionHandler)
with(scope) {
for (index in 0..10) {
launch(CoroutineName("子协程$index")) {
if (index % 3 == 0) {
println("${Thread.currentThread().name}:"+"$index 将抛出异常")
throw NullPointerException("子协程${index}空指针异常")
} else {
println("${Thread.currentThread().name}正常执行:"+"$index")
}
}
}
}
}
}
运行结果:
