You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 10:14:56