协程中并发请求获取结果记录

coroutineScope和supervisorScope都是用来创建一个CoroutineScope并执行代码块,区别在于coroutineScope的 coroutine是一个ScopeCoroutine,而supervisorScope的coroutine是一个SupervisorCoroutine。SupervisorCoroutine继承自ScopeCoroutine但是重写了其父类JobSupport的方法childCancelled(cause:Throwable):Boolean并返回false,这就是它们之间的唯一区别。

在coroutineScope中,只要任意一个子协程发生异常,整个scope都会执行失败,并且其余的所有子协程都会被取消而在supervisorScope中,一个子协程的异常不会影响整个scope的执行,也不会影响其余子协程的执行。

在supervisorScope的代码块中使用多条async执行异步请求,即便请求有异常其他请求依然会执行。一旦使用了async+awiat,请求发生异常还是会抛出异常结束其他请求,这里可以使用CoroutineExceptionHandler进行异常拦截。

想要达到多条请求并发并获取结果就需要对每条请求进行try-catch,异常中填入默认值或空值,这样就能达到需求。如需满足某个请求成功后才能继续其他请求可以使用invokeOnCompletion监听取消请求

        val bean = MutableStateFlow(AllDataBean())
        
        viewModelScope.launch(CoroutineExceptionHandler { _, throwable ->
           Timber.e("接口异常handler:${throwable.message}")
    }) {
        
        supervisorScope {
                val _data1 = async { getData1() }//请求1
                val _data2 = async { getData2() }//请求2
                val _data3 = async { getData3() }//请求3
                val _data4 = async { getData4() }//请求4
                
                // 当_data1请求抛异常时,取消_data2请求
               _data1.invokeOnCompletion { throwable ->
                  throwable?.let { _data2.cancel() }
                }
                
                //调用了await后可能会抛异常,这里给默认值
                val data1 = try {
                    _data1.await().data
                } catch (e: Exception) {
                    Data1Bean()
                }
                val data2 = try {
                    _data2.await().data
                } catch (e: Exception) {
                    Data2Bean()
                }
                val data3 = try {
                    _data3.await().data
                } catch (e: Exception) {
                    mutableListOf<Data3Bean>()
                }
                val data4 = try {
                    _data4.await().data
                } catch (e: Exception) {
                    Data4Bean()
                }

                val allDataBean =
                    AllDataBean(data1, data2, data3, data4)
                    
                   bean.emit(allDataBean) 
             }
        }