Android 协程 异常捕获 异常的传播特性

Posted 安果移不动

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 协程 异常捕获 异常的传播特性相关的知识,希望对你有一定的参考价值。

    @Test
    fun `test exception propagation`() = runBlocking<Unit> 
        val job = GlobalScope.launch 
            try 
                throw IndexOutOfBoundsException()
             catch (e: Exception) 
                println("Caught: $e")
            
        
        job.join()
        val deferred = GlobalScope.async 
            throw ArithmeticException()
        
        try 
            deferred.await()
         catch (e: Exception) 
            println("Caught: $e")
        

        delay(1000)

    

launch的异常是再方法体里面 无论是否执行 

 job.join()

都会报错/

而async的异常则是需要在await的时候才会抛出来

不执行则不会抛出来异常

  @Test
    fun `test exception propagation2`() = runBlocking<Unit> 
        val scope = CoroutineScope(Job())
        val job = scope.launch 
            //非根协程的异常 launch就会立即抛出异常
            async 
                throw IllegalArgumentException()
            
        
        job.join()

    

 异常的传播特性

当一个协程由于一个异常而运行失败时,它会传播这个异常并传递给他的父级。接下来,

父级会

1、取消它自己的子级

2、取消它自己

3、将异常传播并传递给它的父级

很对情况下这不是我们想要的 可以是用

SupervisorJob

   @Test
    fun `test SupervisorJob`() = runBlocking<Unit> 
        val supervisor = CoroutineScope(SupervisorJob())
        val job1 = supervisor.launch 
            delay(1000)
            println("child 1")
            throw IllegalArgumentException()
        

        val job2 = supervisor.launch 
            try 
                delay(Long.MAX_VALUE)
             finally 
                println("child 2 finished")
            
        
        joinAll(job1, job2)


    

 这是一个进行中的状态。程序依然在执行

这说明他不会影响它的child协程的执行

换成Job后

  val supervisor = CoroutineScope(Job())

 程序会执行结束。 和我们上面说的生命周期一样。

也可以是用

supervisorScope 效果是和SupervisorJob 一样的

    @Test
    fun `test SupervisorScope`() = runBlocking<Unit> 
        supervisorScope 
            launch 
                delay(1000)
                println("child 1")
                throw IllegalArgumentException()
            

            launch 
                try 
                    delay(Long.MAX_VALUE)
                 finally 
                    println("child 2 finished")
                
            


        


    

但是如果父协程的抛出了异常。子协程也会跟着退出

 @Test
    fun `test SupervisorScope2`() = runBlocking<Unit> 
        supervisorScope 
            try 
                val child = launch 
                    println("The child is sleeping")
                    delay(Long.MAX_VALUE)
                
             finally 
                println("The child is over")

            
            yield()
            println("Throwing an exception from the scope")
            throw AssertionError()


        


    

 捕获的异常的时机与位置

 

 @Test
    fun `test CoroutineExceptionHandler`() = runBlocking<Unit> 
        val coroutineExceptionHandler = CoroutineExceptionHandler  _, exception ->
            println("Caught $exception")
        
        val job1 = GlobalScope.launch(coroutineExceptionHandler) 
            throw AssertionError()
        
        val job2 = GlobalScope.async(coroutineExceptionHandler) 
            throw ArithmeticException()
        
        job1.join()
        job2.await()

    

 

  @Test
    fun `test CoroutineExceptionHandler2`() = runBlocking<Unit> 
        val coroutineExceptionHandler = CoroutineExceptionHandler  _, exception ->
            println("Caught $exception")
        
        val scope = CoroutineScope(Job())
        val job = scope.launch(coroutineExceptionHandler) 
            launch 
                throw IllegalArgumentException()
            
        
        job.join()

    

    @Test
    fun `test CoroutineExceptionHandler3`() = runBlocking<Unit> 
        val coroutineExceptionHandler = CoroutineExceptionHandler  _, exception ->
            println("Caught $exception")
        
        val scope = CoroutineScope(Job())
        val job = scope.launch() 
            launch(coroutineExceptionHandler) 
                throw IllegalArgumentException()
            
        
        job.join()

    

test CoroutineExceptionHandler2的异常是可以捕获到的

test CoroutineExceptionHandler3的异常是捕获不到的。内部是不行的外部可以。

以上是关于Android 协程 异常捕获 异常的传播特性的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

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

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