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

Kotlin协程:如何等待多API请求完成后更新UI?

问题分析

你的核心问题在于API请求的异步逻辑和协程的等待逻辑不匹配:

  • getScore方法使用Retrofit的enqueue发起请求,这是基于回调的异步操作,协程中调用getScore(type)只是触发了请求,并不会等待API响应返回就直接执行后续代码。
  • 因此job.join()会在所有请求发起后立刻完成,而非等待所有请求的响应结果回来,导致加载器提前关闭。即使改用async,如果内部还是用回调式的API调用,也会出现同样的问题。
解决方案

步骤1:将Retrofit回调转为协程挂起函数

Retrofit 2.6.0及以上版本原生支持协程,我们可以用await()替代enqueue,把API调用改成挂起函数,让协程能够等待请求完成:

private suspend fun getScore(type: String): Score? {
    return try {
        val response = MyApi.getScores(type).await()
        if (response.isSuccessful) {
            response.body()
        } else {
            // 处理请求失败(比如状态码非2xx)
            null
        }
    } catch (e: Exception) {
        // 处理网络异常、超时等情况
        null
    }
}

如果你的Retrofit版本低于2.6.0,需要添加kotlinx-coroutines-retrofit依赖才能使用await()扩展函数

步骤2:用协程并行执行并等待所有请求完成

改用lifecycleScope(或viewModelScope,根据组件生命周期选择)管理协程,避免内存泄漏,同时用async+awaitAll实现并行请求并等待全部完成:

private fun getScoreForType() {
    lifecycleScope.launch {
        showLoader() // 显示加载器
        // 并行发起所有API请求,每个请求返回一个Deferred对象
        val deferredTasks = types.map { type ->
            async(Dispatchers.IO) {
                getScore(type)
            }
        }
        // 等待所有请求完成,获取全部结果
        val scoreResults = deferredTasks.awaitAll()
        // 处理所有有效结果,更新UI
        scoreResults.forEachNotNull { score ->
            setScore(score)
        }
        // 所有请求完成后关闭加载器
        dismissLoader()
    }
}
关键说明
  • 用lifecycleScope/viewModelScope替代手动创建的CoroutineScope:这类生命周期绑定的协程会在组件销毁时自动取消,避免内存泄漏。
  • async用于创建并行的异步任务,awaitAll()会阻塞当前协程,直到所有Deferred任务都完成,确保所有API响应都返回后再执行UI更新和关闭加载器的逻辑。
  • 挂起函数getScore让协程能够等待API请求完成,而非通过回调异步执行,保证了协程等待逻辑的准确性。

内容的提问来源于stack exchange,提问作者MADi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 09:24:43