Android中依赖型异步函数嵌套代码优化咨询
优化依赖型异步任务的结果处理方案
针对Android开发中依赖型异步任务嵌套when导致可读性差的问题,推荐以下几种扁平化的实现方式:
方案一:自定义扩展函数实现链式调用
给MyResult密封类添加扩展函数,让成功/失败的处理逻辑可以链式串联,避免嵌套:
1. 扩展函数定义
sealed class MyResult<out T> { data class Success<out T>(val data: T) : MyResult<T>() data class Failure(val error: Throwable) : MyResult<Nothing>() } // 仅在Success状态时执行后续异步任务 fun <T, R> MyResult<T>.onSuccess(block: (T) -> MyResult<R>): MyResult<R> { return when (this) { is MyResult.Success -> block(data) is MyResult.Failure -> this } } // 处理Failure状态,支持链式调用 fun <T> MyResult<T>.onFailure(block: (Throwable) -> Unit): MyResult<T> { if (this is MyResult.Failure) { block(error) } return this }
2. 使用示例
function1UseCase.getResult1() .onFailure { /* 处理function1执行失败的逻辑 */ } .onSuccess { result1Data -> function2UseCase.getResult2(result1Data) } .onFailure { /* 处理function2执行失败的逻辑 */ } .onSuccess { result2Data -> // 继续执行后续依赖任务,比如function3 }
方案二:Kotlin协程+分阶段判断
将异步任务改造为挂起函数,在协程中按顺序执行,通过顺序判断替代嵌套:
1. 改造UseCase为挂起函数
suspend fun getResult1(): MyResult<Data1> { return try { val data = firebaseApi.fetchData1() // 异步操作 MyResult.Success(data) } catch (e: Exception) { MyResult.Failure(e) } } suspend fun getResult2(data1: Data1): MyResult<Data2> { return try { val data = otherApi.fetchData2(data1) // 依赖data1的异步操作 MyResult.Success(data) } catch (e: Exception) { MyResult.Failure(e) } }
2. 协程中执行
viewModelScope.launch { // 执行任务1 val result1 = function1UseCase.getResult1() if (result1 is MyResult.Failure) { // 处理任务1失败 return@launch } // 任务1成功后执行任务2 val result2 = function2UseCase.getResult2(result1.data) if (result2 is MyResult.Failure) { // 处理任务2失败 return@launch } // 任务2成功后执行后续逻辑 }
如果需要更简洁的异常处理,可给MyResult添加getOrThrow扩展,结合runCatching:
fun <T> MyResult<T>.getOrThrow(): T { return when (this) { is MyResult.Success -> data is MyResult.Failure -> throw error } } // 使用方式 viewModelScope.launch { runCatching { val data1 = function1UseCase.getResult1().getOrThrow() val data2 = function2UseCase.getResult2(data1).getOrThrow() // 后续逻辑 }.onFailure { e -> // 统一处理所有失败(适合无需区分失败阶段的场景) } }
方案三:Flow串联数据流
如果需要处理更复杂的异步数据流(比如持续监听、多阶段任务联动),可使用Kotlin Flow:
1. 改造UseCase返回Flow
fun getResult1Flow(): Flow<MyResult<Data1>> = flow { val data = firebaseApi.fetchData1() emit(MyResult.Success(data)) }.catch { emit(MyResult.Failure(it)) } fun getResult2Flow(data1: Data1): Flow<MyResult<Data2>> = flow { val data = otherApi.fetchData2(data1) emit(MyResult.Success(data)) }.catch { emit(MyResult.Failure(it)) }
2. 串联任务并监听
viewModelScope.launch { function1UseCase.getResult1Flow() .flatMapConcat { result1 -> // 任务1成功则执行任务2,否则直接传递失败结果 if (result1 is MyResult.Success) { function2UseCase.getResult2Flow(result1.data) } else { flow { emit(result1 as MyResult.Failure) } } } .collect { result -> when (result) { is MyResult.Success -> { /* 处理最终成功结果 */ } is MyResult.Failure -> { /* 根据失败阶段处理逻辑 */ } } } }
方案选型建议
- 链式扩展函数:适合简单的2-3个依赖任务,代码最简洁,扁平化效果明显。
- 协程分阶段判断:适合需要区分每个任务失败场景的业务逻辑,逻辑清晰易维护。
- Flow:适合需要数据流监听、多阶段异步联动或生命周期感知的复杂场景。
内容的提问来源于stack exchange,提问作者Electrocode
相关产品推荐
相关产品推荐

