【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )


文章目录

  • ​​一、Android 协程中出现异常导致应用崩溃​​
  • ​​二、Android 协程中使用协程异常处理器捕获异常​​
  • ​​三、Android 全局异常处理器​​






一、Android 协程中出现异常导致应用崩溃



在前几篇博客示例中 , 协程中 如果出现异常 , 没有进行捕获 , 则程序直接崩溃 , 这种情况下需要进行 异常的捕获 以 避免 Android 应用程序的崩溃 ;



示例代码 :

package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

GlobalScope.launch {
Log.i(TAG, "验证协程中抛出异常")
throw IllegalArgumentException()
}
}
}

执行结果 : 在协程中抛出了异常 , 应用直接退出 ;

15:46:00.444  I  验证协程中抛出异常
15:46:00.486 D Skia GL Pipeline
15:46:00.504 E FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: kim.hsl.coroutine, PID: 26587
java.lang.IllegalArgumentException
at kim.hsl.coroutine.MainActivity$onCreate$1.invokeSuspend(MainActivity.kt:18)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
15:46:00.511 W Force finishing activity kim.hsl.coroutine/.MainActivity
15:46:00.528 I Sending signal. PID: 26587 SIG: 9
---------------------------- PROCESS ENDED (26587) for package kim.hsl.coroutine ----------------------------

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_android






二、Android 协程中使用协程异常处理器捕获异常



在 Android 程序中 , 可以使用 协程异常处理器 CoroutineExceptionHandler 捕获异常 , 将其实例对象传递给 launch 协程构建器 作为参数即可 ;

该参数作为 协程上下文 的 协程异常处理器 CoroutineExceptionHandler 元素 ;



代码示例 :

package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// 创建 协程异常处理器 CoroutineExceptionHandler
val coroutineExceptionHandler = CoroutineExceptionHandler {
coroutineContext, throwable ->

Log.i(TAG, "CoroutineExceptionHandler 中处理异常 " +
"\n协程上下文 ${coroutineContext}" +
"\n异常内容 ${throwable}")
}

GlobalScope.launch {
Log.i(TAG, "验证协程中抛出异常")
throw IllegalArgumentException()
}
}
}

执行结果 : 协程异常处理器 CoroutineExceptionHandler 捕获到了异常 ;

15:47:54.749  I  验证协程中抛出异常
15:47:54.754 I CoroutineExceptionHandler 中处理异常
协程上下文 [kim.hsl.coroutine.MainActivity$onCreate$$inlined$CoroutineExceptionHandler$1@bc6a601, StandaloneCoroutine{Cancelling}@fef2ca6, Dispatchers.Default]
异常内容 java.lang.IllegalArgumentException

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_kotlin_02






三、Android 全局异常处理器



Android 中的 全局异常处理器 , 可以 获取 所有的 协程 中产生的 没有被捕获的异常 ;

  • 无法阻止崩溃 : 全局异常处理器 不能捕获这些异常 进行处理 , 应用程序 还是要崩溃 ;
  • 用于调试上报 : 全局异常处理器 仅用于 程序调试 和 异常上报 场景


全局异常处理器使用步骤如下 :

① 在 app/main/ 目录下创建 resources 目录 , 在 resources 目录下创建 META-INF

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_协程全局异常处理器_03

② 在 META-INF 目录下创建 services

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_协程全局异常处理器_04

③ 在 app/main/resources/META-INF/services 目录下 , 创建 名称为 kotlinx.coroutines.CoroutineExceptionHandler

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_协程异常处理器_05


④ 创建 协程的 全局异常处理器 MyCoroutineExceptionHandler 自定义类 , 需要 实现 CoroutineExceptionHandler 接口 ; 并覆盖接口中的 ​ ​val key​ ​​ 成员变量 和 ​ ​fun handleException(context: CoroutineContext, exception: Throwable) ​ ​ 成员方法 ;

package kim.hsl.coroutine

import android.util.Log
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlin.coroutines.CoroutineContext

class MyCoroutineExceptionHandler : CoroutineExceptionHandler {
val TAG = "MyCoroutineExceptionHandler"

override val key = CoroutineExceptionHandler

override fun handleException(context: CoroutineContext, exception: Throwable) {
Log.i(TAG, "在 MyCoroutineExceptionHandler 全局异常处理器 中处理未捕获异常 " +
"\n协程上下文 ${context}" +
"\n抛出异常 ${exception}")
}
}

⑤ 在 app/main/resources/META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler 文件中配置 协程的 全局异常处理器 MyCoroutineExceptionHandler 自定义类 的全类名 ​ ​kim.hsl.coroutine.MyCoroutineExceptionHandler​ ​ , 如下图所示 :

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_android_06

⑥ 在 Activity 中实现一个 抛出异常的协程 :

package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

GlobalScope.launch() {
Log.i(TAG, "验证协程中抛出异常")
throw IllegalArgumentException()
}
}
}

⑦ 执行上述应用 , 会抛出异常 , 协程中也不进行异常处理 , 此时执行结果如下 :

16:30:53.537  I  验证协程中抛出异常
16:30:53.578 D Skia GL Pipeline
16:30:53.590 I 在 MyCoroutineExceptionHandler 全局异常处理器 中处理未捕获异常
协程上下文 [StandaloneCoroutine{Cancelling}@8252a7e, Dispatchers.Default]
抛出异常 java.lang.IllegalArgumentException
16:30:53.593 E FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: kim.hsl.coroutine, PID: 8808
java.lang.IllegalArgumentException
at kim.hsl.coroutine.MainActivity$onCreate$1.invokeSuspend(MainActivity.kt:18)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
16:30:53.599 W Force finishing activity kim.hsl.coroutine/.MainActivity
16:30:53.608 I Sending signal. PID: 8808 SIG: 9
16:30:53.627 I Process kim.hsl.coroutine (pid 8808) has died: cch CRE
---------------------------- PROCESS ENDED (8808) for package kim.hsl.coroutine ----------------------------

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )_协程_07

在 MyCoroutineExceptionHandler 全局异常处理器 中处理未捕获异常 , 但是程序依然崩溃 , 可以在 全局异常处理器 中获取到异常信息 ;


【Kotlin 协程】协程异常处理 ③ ( 协程异常处理器 CoroutineExceptionHandler 捕获异常 | 验证 CoroutineScope 协程的异常捕捉示例 )

一、协程异常处理器 CoroutineExceptionHandler 捕获异常1、对比 launch 和 async 创建的

【Kotlin 协程】协程异常处理 ① ( 根协程异常处理 | 自动传播异常 | 在协程体捕获异常 | 向用户暴露异常 | 在 await 处捕获异常 | 非根协程异常处理 | 异常传播特性 )

一、协程异常处理、二、根协程自动传播异常、1、异常抛出点 ( 协程体抛出异常 )、2、异常

【Kotlin 协程】协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )

一、Android 协程中出现异常导致应用崩溃、二、Android 协程中使用协程异常

2021-03-11:go中,协程内部再启用协程,它们是没关系,对吧?外部协程奔溃,内部协程还会执行吗?外部协程执行结束的时候,如何让内部协程也停止运行?golang原生提供的包里,让内部协程停止运行

2021-03-11:go中,协程内部再启用协程,它们是没关系,对吧?外部协程奔溃,内部协程还会执行吗?外部协程执行结束的时候,如何让内部协程也停止运行?golang原生提供的包里,让内部协程停止运行,如何实现?福哥答案2021-03-11:1.外部协程和内部协程没关系。2.如果程序不奔溃,不会影响内部协程继续执行。如果没做特殊处理,整个程序会奔溃。3.三种方式:共享变量作为标志位,通道,上下文context。这三种方式均是协作式中断,不是抢占式。对于程序员,是无法实现抢占式中断的。如果能实现抢占

【Kotlin 协程】协程异常处理 ⑤ ( 异常传播的特殊情况 | 取消子协程示例 | 子协程抛出异常后父协程处理异常时机示例 | 异常聚合 | 多个子协程抛出的异常会聚合到第一个异常中 )

一、异常传播的特殊情况、1、取消子协程示例、2、子协程抛出异常后父协程处理异常时