You need to enable JavaScript to run this app. Kotlin协程中如何等待Retrofit的getData()请求执行完成
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin协程中如何等待Retrofit的getData()请求执行完成

核心问题

你现在的写法存在逻辑冲突:loadData()是同步返回值的函数,但内部的Retrofit网络请求是通过viewModelScope.launch启动的异步协程任务,函数执行到return cryptoDatas的时候协程里的网络请求还未执行完成,自然拿不到最新的请求结果。

推荐改造方案

方案1:采用响应式编程逻辑,通过LiveData回调结果(最优适配现有代码)

你已经定义了currency这个LiveData存储请求结果,完全不需要让loadData()同步返回值,后续要执行的操作直接观察currency的变化即可:
首先改造loadData函数,去掉无意义的返回值,简化冗余的线程切换代码:

fun loadData() {
    val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(CryptoAPI::class.java)

    viewModelScope.launch {
        // Retrofit挂起函数自动支持后台调度,不需要手动切Dispatchers.IO
        val response = retrofit.getData()
        // viewModelScope默认运行在主线程,不需要手动切Dispatchers.Main
        if (response.isSuccessful){
            response.body()?.let {
                cryptoDatas = ArrayList(it)
                currency.value = cryptoDatas
                progressBarStatus.value = false
                println(response.isSuccessful)
            }
        } else {
            println(response.isSuccessful)
            // 可自行增加错误状态LiveData回调
        }
    }
}

然后在你需要执行后续操作的地方(比如Activity/Fragment),观察currency的变化,拿到结果后再执行后续逻辑:

// 示例代码,写在Activity/Fragment的onCreate/onViewCreated中
viewModel.currency.observe(this) { cryptoList ->
    // 这里拿到请求返回的结果,直接执行你需要的后续操作
}

方案2:如果确实需要同步等待请求结果再返回,将loadData改为挂起函数

如果你的业务场景需要函数直接返回请求结果,把loadData改成挂起函数,去掉内部的launch包装,直接执行请求:

suspend fun loadData(): ArrayList<CryptoData>? {
    val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(CryptoAPI::class.java)

    val response = retrofit.getData()
    return if (response.isSuccessful) {
        response.body()?.let {
            cryptoDatas = ArrayList(it)
            currency.postValue(cryptoDatas)
            progressBarStatus.postValue(false)
            println(response.isSuccessful)
            cryptoDatas
        }
    } else {
        println(response.isSuccessful)
        null
    }
}

调用这个挂起函数时,在协程作用域中调用即可,调用处可以自然等待执行完成再执行后续代码:

// 示例调用,写在ViewModel或者Activity/Fragment的协程中
viewModelScope.launch {
    val result = loadData()
    // 这里的result就是请求结果,直接执行后续操作
}

之前尝试不生效的原因

  • runBlocking会阻塞当前线程,如果你在主线程调用会直接卡住UI,不符合Android开发规范
  • async{}.await()之前未生效是因为你没有把loadData改成挂起函数,外层还是同步返回,自然拿不到异步执行的结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 16:57:03