[英]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.