簡體   English   中英

Kotlin 協程等待 Retrofit 響應

[英]Kotlin Coroutine wait for Retrofit Response

我正在嘗試將 Android MVVM模式與存儲庫 class 和Retrofit用於網絡調用。 我有一個常見的問題是我無法讓協程等待網絡響應返回。

此方法在我的ViewModel class 中:

private fun loadConfigModel() {
    val model = runBlocking {
        withContext(Dispatchers.IO) {
            configModelRepository.getConfigFile()
        }
    }
    configModel.value = model
}

ConfigModelRepository ,我有這個:

suspend fun getConfigFile(): ConfigModel {
    val configString = prefs.getString(
        ConfigViewModel.CONFIG_SHARED_PREF_KEY, "") ?: ""

    return if (configString.isEmpty() || isCacheExpired()) {
        runBlocking { fetchConfig() }
    } else {
        postFromLocalCache(configString)
    }
}

private suspend fun fetchConfig(): ConfigModel {
    return suspendCoroutine { cont ->
         dataService
            .config()  // <-- LAST LINE CALLED
            .enqueue(object : Callback<ConfigModel> {
                 override fun onResponse(call: Call<ConfigModel>, response: Response<ConfigModel>) {
                    if (response.isSuccessful) {
                        response.body()?.let {
                            saveConfigResponseInSharedPreferences(it)
                            cont.resume(it)
                        }
                    } else {
                        cont.resume(ConfigModel(listOf(), listOf()))
                    }
                }

                override fun onFailure(call: Call<ConfigModel>, t: Throwable) {
                    Timber.e(t, "config fetch failed")
                    cont.resume(ConfigModel(listOf(), listOf()))
                }
            })
    }
}

我的代碼一直運行到dataService.config() 它永遠不會進入onResponseonFailure 網絡調用正確地進行並返回(我可以使用 Charles 看到這一點),但協程似乎沒有在監聽回調。

所以,我的問題是通常的問題。 如何讓協程阻塞,以便它們等待來自Retrofit的回調? 謝謝。

問題一定是response.body()返回null因為這是唯一缺少對cont.resume()調用的情況。 確保在這種情況下也調用cont.resume()並且您的代碼至少應該不會卡住。

但就像 CommonsWare 指出的那樣,更好的辦法是升級到 Retrofit 2.6.0 或更高版本並使用本機suspend支持而不是滾動您自己的suspendCoroutine邏輯。

您還應該完全停止使用runBlocking 在第一種情況下,改為launch(Dispatchers.Main)協程並將configModel.value = model移動到其中。 在第二種情況下,您可以刪除runBlocking並直接調用fetchConfig()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM