如何等待 retrofit.getData() 完成 Kotlin 协程

How to wait for retrofit.getData() complete Kotlin Coroutines

我正在从 API 获取数据,我需要等到作业完成。因为 MutableLiveData。 当它工作时 response.isSusccesful=false 然后它变成 true。我如何等到 retrofit.getData() 完成。我试过 runblocking 但它不是合适的方法。我尝试了 async{} 和 await() 但我也没成功。

fun loadData():ArrayList<CryptoData> {

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

    job = viewModelScope.launch {
        withContext(Dispatchers.IO){
            val response = retrofit.getData()

            withContext(Dispatchers.Main){

                if (response.isSuccessful){
                    response.body()?.let {
                        cryptoDatas = ArrayList(it)
                        currency.value = cryptoDatas
                        progressBarStatus.value = false
                        println(response.isSuccessful)

                    }
                }
                else{
                    println(response.isSuccessful)
                }
            }
        }
    }

    return cryptoDatas
}

如果你的 getData() 是一个 suspend 函数你应该没问题,因为默认情况下协同程序中的代码是顺序的,这意味着 val response = retrofit.getData() 下面的任何东西都不能 运行 直到getData() returns.

如果它不只是使它成为一个 suspend 函数,因为 Retrofit 本身就支持它。

@GET("...")
suspend fun getData(): Response<...>

关于这个问题,你可以打电话给job.join()等待工作完成,但对你来说这根本帮不了你。 join() 是一个挂起函数,因此必须从另一个 suspend 函数或另一个协程调用它。

首先,您应该确保 getData() 被定义为一个挂起函数,这样您就不必欺骗那些 withContext 包装器。调用正确编写的挂起函数时不需要它们,因为正确的挂起函数不会阻塞,如果需要特定的挂起函数,它们会在内部委托给适当的调度程序。

那么你有两个选择。

  1. 不是从函数返回某些东西,而是将结果发布到 LiveData(或 SharedFlow/StateFlow)。外部 class 可以调用此函数并观察 LiveData 以处理结果。
private val _cryptoData = MutableLiveData<ArrayList<CryptoData>>()
val cryptoData: LiveData<ArrayList<CryptoData>> = _cryptoData

fun loadData() {

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

    viewModelScope.launch {
        val response = retrofit.getData()
        if (response.isSuccessful){
            response.body()?.let {
                cryptoData.value = ArrayList(it)
                currency.value = it
                progressBarStatus.value = false
                println(response.isSuccessful)
            } 
        else {
            println(response.isSuccessful)
        }
    }
}
  1. 使loadData()成为暂停功能。你的外部 class 可以使用协程调用它,然后按顺序对结果进行处理。
suspend fun loadData(): List<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 {
            currency.value = it
            progressBarStatus.value = false
            println(response.isSuccessful)
            ArrayList(it)
        }
    } else {
        println(response.isSuccessful)
        null
    }
}

但我从字里行间看出,这是您每次显示此片段或 Activity 时加载的数据。所以你应该使用选项 1,除非你将这个函数设为私有并从 init 块中调用它。这样,外部class只需要观察LiveData,如果用户旋转设备,就不会每次都重新开始请求,延迟数据加载完成。