[英]Android kotlin coroutines async await
在我的 Viewmodel class 中,我执行以下代码:
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))
}
)
}
我的期望是这样的:
但它不是那样工作的。 即使我使用了异步等待,在我的 API 调用完成之前程序转到 checkFavoriteStatus(homeItemsTest) 行。 我认为异步等待暂停/阻止正在执行异步代码的协程(在这种情况下,正在执行我的整个初始化块的协程..?我有什么问题吗?
如果是,那么使用协程等待我的 API 调用完成然后 go 到下一个代码的最佳方法是什么?
编辑这些是 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() }
}
private suspend fun GetHomePage() = viewModelScope.launch(Dispatchers.IO) {
restService.getHomepage().getResult(
success = { value ->
homeItemsTest = value
checkFavoriteStatus(value)
},
genericError = { _, message ->
error.postValue(message)
},
networkError = {
error.postValue(TranslationManager.getString(TKeys.LOGIN_NETWORK_ERROR))
}
)
}
您对 async-await 部分的看法大部分是正确的。 问题出在getHomepageItems()
function 中。 你launch()
一切都是异步的,因此这个 function 立即返回。 此外, getResult()
似乎也是异步的。
使此 function suspend
并使所有代码同步。 生成的代码可能如下所示,但可能需要额外的调整:
private suspend fun getHomepageItems() {
suspendCoroutine<Unit> { cont ->
restService.getHomepage().getResult(
success = { value ->
homeItemsTest = value
cont.resume(Unit)
},
genericError = { _, message ->
error.postValue(message)
cont.resume(Unit)
},
networkError = {
error.postValue(TranslationManager.getString(TKeys.LOGIN_NETWORK_ERROR))
cont.resume(Unit)
}
)
}
}
根据您使用的 rest 客户端库,执行起来可能要容易得多,因为许多此类库已经支持协程和挂起功能。 在这种情况下,他们通常会提供暂停 API,因此您不必自己将回调转换为暂停。 查阅图书馆的文档。
如果您想在 API 调用完成后做某事,您可以执行以下操作
init {
viewModelScope.launch(Dispatchers.IO) {
homepageItemsCall = getHomepageItems()
carouselItemsCall = getCarouselItems()
}.invokeOnCompletion{
checkFavoriteStatus(homeItemsTest)
carouselItems.postValue(carouselItemsTest)
}
}
尝试使 function getHomepageItems
和getCarouselItems
suspend
,如下所示:
private suspend fun getHomepageItems() {
restService.getHomepage().getResult(
success = { value ->
homeItemsTest = value
},
genericError = { _, message ->
error.postValue(message)
},
networkError = {
error.postValue(TranslationManager.getString(TKeys.LOGIN_NETWORK_ERROR))
}
)
}
因为async
创建了一个协程来运行代码, await
会等待它并从中获取结果。 但是在您的代码中, async
中的协程是创建另一个await
不会等待它的协程
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.