https://www.youtube.com/watch?v=VWlwkqmTLHc&list=PLQkwcJG4YTCQcFEPuYGuv54nYai_lwil_&index=11

协程总结

抓不到的异常

如果我们在launch外面try catch 意图捕获异常的话

   //无法捕获异常导致奔溃
    private fun cannotCatchException() {
        lifecycleScope.launch {
            try {
                //外面catch不到的
                launch {
                    //只能在这里面try catch,直接捕获
                    throw Exception()
                }

            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

如果不是在抛出异常的地方直接捕获异常,那么在外面是捕获不到的,会直接导致应用奔溃

asyn不会奔溃

如果async中发生了异常,如果没有调用await,则程序不会奔溃

 private fun asyncWonCrash() {
        lifecycleScope.async {
            val string = async {
                delay(1000)
                throw Exception("error")
            }
        }
    }

我们在async中直接抛出异常,但是应用没有奔溃

但如果在launch中运行,需要再await的地方添加捕获,不然程序奔溃

  private fun asyncWonCrash() {
        val result = lifecycleScope.async {
            val string = async {
                delay(1000)
                throw Exception("error")
                "result"
            }
            println("linlian"+string.await())
        }

        lifecycleScope.launch {
            try {
                result.await()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

当时如果只是看到这里,以为就结束了!!!!

no,上面的这个异常捕获,有一个很大的陷阱,之前的文章也有提到

就是我们可能吧 cancellation exception也捕获了,导致协程任务无法取消!!!!

那一般是怎么处理了,可以根coroutinescope添加coroutineexception handler

    private val exceptionHander = CoroutineExceptionHandler { ctx, throwale ->

        println("handle exception $throwale")
    }

    private fun exceptionHandlerdemo() {
        lifecycleScope.launch(exceptionHander) {
            launch {
                throw Exception("error")
            }
        }
    }

这样内部子任务的异常都可以被捕获

协程的某个子任务异常了,那其他的任务会怎样呢?

那这个和所在的scope的类型有关,如果是个普通的sceop

当有一个子协程异常了,其他的协程也取消了

 private fun differentScope() {
        CoroutineScope(Dispatchers.Main).launch(exceptionHander) {
            launch {
                delay(300)
                throw Exception("linlian 1 failed")
            }
            launch {
                delay(500)
                println("linlian 2 success")
            }

        }
    }

但是像viewmodescope这些,还有globalscope,一般我们一个子协程异常,是不会影响到其他的协程的,这个是什么原因呢

viewmodel的源码中

val ViewModel.viewModelScope: CoroutineScope
        get() {
            val scope: CoroutineScope? = this.getTag(JOB_KEY)
            if (scope != null) {
                return scope
            }
            return setTagIfAbsent(JOB_KEY,
                CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
        }
SupervisorJob()

Creates a supervisor job object in an active state. Children of a supervisor job can fail independently of each other.

互不影响


    private fun differentScope() {
        CoroutineScope( Dispatchers.Main).launch(exceptionHander) {
            supervisorScope {
                launch {
                    delay(300)
                    throw Exception("linlian 1 failed")
                }
                launch {
                    delay(500)
                    println("linlian 2 success")
                }

            }
            
        }
    }

所以加上 supervisorScope ,任务2就不会因为任务1的异常而被影响,取消了。

另外如果cancellation exception被捕获的话,任务也不会取消,会一直运行下去

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐