【发布时间】:2022-01-18 15:15:00
【问题描述】:
在我的 Viewmodel 类中,我执行下一个代码:
init {
viewModelScope.launch(Dispatchers.IO) {
val homepageItemsCall = async { getHomepageItems() }
val carouselItemsCall = async { getCarouselItems() }
homepageItemsCall.await()
carouselItemsCall.await()
checkFavoriteStatus(homeItemsTest)
carouselItems.postValue(carouselItemsTest)
}
}
这就是我的 homepageItemsCall 的样子:
private fun getHomepageItems() = viewModelScope.launch(Dispatchers.IO) {
restService.getHomepage().getResult(
success = { value ->
homeItemsTest = value
},
genericError = { _, message ->
error.postValue(message)
},
networkError = {
error.postValue(TranslationManager.getString(TKeys.LOGIN_NETWORK_ERROR))
}
)
}
我的期望是这样的:
- 我在 ViewmodelScope 上创建了一个协程,它将执行 init 块中的代码。
- 因为我使用的是异步等待,所以在我的 API 调用完成之前我的代码不会被执行。这意味着我的两个 API 调用都将进入成功/失败状态,之后,我的代码可以进入下一行:“checkFavoriteStatus(homeItemsTest)”。
但它不是那样工作的。即使我使用了异步等待,在我的 API 调用完成之前程序会转到 checkFavoriteStatus(homeItemsTest) 行。我认为 async await 挂起/阻塞正在执行异步代码的协程(在这种情况下,协程正在执行我的整个 init 块..?我有什么问题吗?
如果是,那么等待我的 API 调用完成然后使用协程转到下一个代码的最佳方法是什么?
编辑这些是getHomePage和getResult函数:
suspend fun <T> ResultWrapper<T>.getResult(
success: suspend (value: T) -> Unit,
genericError: (suspend (code: Int?, message: String?) -> Unit)? =
null,
networkError: (suspend () -> Unit)? = null,
error: (suspend () -> Unit)? = null
) {
when (this) {
is ResultWrapper.Success -> {
success(value)
}
is ResultWrapper.GenericError -> {
genericError?.let { it(code, errorMessage) }
}
is ResultWrapper.NetworkError -> {
networkError?.let { it() }
}
}
if (this is ResultWrapper.NetworkError || this is ResultWrapper.GenericError)
error?.let { it() }
}
suspend fun getHomepage() = safeApiCall(Dispatchers.IO) {
apiClient.getHomepageElements()
}
【问题讨论】:
-
是
restService.getHomepage()还是.getResult()挂起?如果它们不是 getHomepageItems 函数将立即返回,您可能不希望在这里。 -
@ArpitShukla 是的,它们都是挂起函数
-
@Kratos 哦,这很奇怪。通常,只有一个等待网络的操作,它要么是挂起,要么是基于回调。在您的情况下,代码中似乎有 3 个不同的地方发生等待。这个休息客户端是什么?
getHomepage()和getResult()是库提供的还是你实现的?你能分享他们的源代码吗? -
@broot 当然没问题。看看我加的。 GetResult 是一个扩展函数,我们添加它是为了更好地处理错误。 GetHomePage 是 ViewModel 中的标准函数。
-
所以,首先,您可能提供了一个不同的、名称相似的函数:
GetHomePage()而不是restService.getHomepage()。其次,这段代码中有一个奇怪的习惯,将所有函数标记为suspend,即使它们并没有真正挂起并以launch()启动每个函数。launch()使跟踪操作变得不可能/更加困难,请等待它完成并获得结果。
标签: android kotlin kotlin-coroutines