Kotlin Compose中依赖型多API调用的代码优化方案咨询
优化嵌套依赖API调用的Kotlin Compose写法
原代码因多层嵌套collect导致代码可读性差,以下是几种简洁的优化方案:
方案1:利用Flow操作符链式处理(推荐)
改造ViewModel的API方法
将触发式方法改为返回Flow<DataState>,避免依赖外部StateFlow传递结果:
// ViewModel代码 fun getDataOne(key: String): Flow<DataState<DataOne>> { return repository.getDataOne(key) } fun getDataTwo(value1: String, value2: String): Flow<DataState<DataTwo>> { return repository.getDataTwo(value1, value2) } fun getDataThree(valueID: String, valueName: String): Flow<DataState<DataThree>> { return repository.getDataThree(valueID, valueName) }
View层链式调用
通过flatMapConcat串联依赖请求,配合filterIsInstance过滤成功状态,彻底消除嵌套:
// Compose View代码 scope.launch { viewModel.getDataOne(key) .filterIsInstance<DataState.Success<DataOne>>() .flatMapConcat { successOne -> viewModel.getDataTwo(successOne.data.value1, successOne.data.value2) } .filterIsInstance<DataState.Success<DataTwo>>() .flatMapConcat { successTwo -> viewModel.getDataThree(successTwo.data.valueID, successTwo.data.valueName) } .filterIsInstance<DataState.Success<DataThree>>() .collect { successThree -> // 执行后续业务逻辑 } }
方案2:挂起函数+顺序调用
如果API仅需返回单次结果,可将ViewModel方法改为挂起函数:
改造ViewModel方法
// ViewModel代码 suspend fun getDataOne(key: String): DataState<DataOne> { return repository.getDataOne(key).first() } suspend fun getDataTwo(value1: String, value2: String): DataState<DataTwo> { return repository.getDataTwo(value1, value2).first() } suspend fun getDataThree(valueID: String, valueName: String): DataState<DataThree> { return repository.getDataThree(valueID, valueName).first() }
View层顺序执行请求
用普通分支判断替代嵌套collect:
// Compose View代码 scope.launch { val dataOneState = viewModel.getDataOne(key) if (dataOneState is DataState.Success) { val dataTwoState = viewModel.getDataTwo(dataOneState.data.value1, dataOneState.data.value2) if (dataTwoState is DataState.Success) { val dataThreeState = viewModel.getDataThree(dataTwoState.data.valueID, dataTwoState.data.valueName) if (dataThreeState is DataState.Success) { // 处理最终结果 } } } }
方案3:业务逻辑下沉到ViewModel(最佳实践)
将链式请求逻辑封装在ViewModel中,View层仅负责监听最终结果,进一步简化UI代码:
ViewModel封装请求逻辑
// ViewModel代码 private val _finalDataState = MutableStateFlow<DataState<DataThree>>(DataState.Idle) val finalDataState: StateFlow<DataState<DataThree>> = _finalDataState fun fetchAllDependentData(key: String) { viewModelScope.launch { runCatching { val dataOne = getDataOne(key).takeSuccess() val dataTwo = getDataTwo(dataOne.value1, dataOne.value2).takeSuccess() getDataThree(dataTwo.valueID, dataTwo.valueName).takeSuccess() }.fold( onSuccess = { finalData -> _finalDataState.emit(DataState.Success(finalData)) }, onFailure = { error -> _finalDataState.emit(DataState.Error(error)) } ) } } // 扩展函数:提取Success状态数据,失败则抛出异常 private fun <T> DataState<T>.takeSuccess(): T { return if (this is DataState.Success) data else throw IllegalStateException("Request failed with state: $this") }
View层监听结果
// Compose View代码 scope.launch { viewModel.fetchAllDependentData(key) viewModel.finalDataState.collect { state -> when (state) { is DataState.Success -> { // 处理成功结果 } is DataState.Error -> { // 处理错误情况 } else -> {} } } }
内容的提问来源于stack exchange,提问作者Lloyd Munyai
相关产品推荐
相关产品推荐

