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

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 协程协程异常处理 ④ ( 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 ----------------------------





二、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, StandaloneCoroutineCancelling@fef2ca6, Dispatchers.Default]
                 异常内容 java.lang.IllegalArgumentException





三、Android 全局异常处理器



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

  • 无法阻止崩溃 : 全局异常处理器 不能捕获这些异常 进行处理 , 应用程序 还是要崩溃 ;
  • 用于调试上报 : 全局异常处理器 仅用于 程序调试 和 异常上报 场景 , 也就是出现了异常 , 将异常通知开发者 ;

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

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

② 在 META-INF 目录下创建 services 目录 ,

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


④ 创建 协程的 全局异常处理器 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 , 如下图所示 :

⑥ 在 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  IMyCoroutineExceptionHandler 全局异常处理器 中处理未捕获异常 
                 协程上下文 [StandaloneCoroutineCancelling@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 ----------------------------

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

以上是关于Kotlin 协程协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 协程协程异常处理 ② ( SupervisorJob 协程 | supervisorScope 协程作用域构建器函数 )

Kotlin 协程协程异常处理 ② ( SupervisorJob 协程 | supervisorScope 协程作用域构建器函数 )

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

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

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

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