簡體   English   中英

Android kotlin 協程異步等待

[英]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))
        }
    )
}

我的期望是這樣的:

  1. 我在 ViewmodelScope 上創建了一個協程,它將在 init 塊中執行代碼。
  2. 因為我使用的是異步等待,所以在我的 API 調用完成之前,我的代碼不會被執行。 這意味着我的兩個 API 調用都將 go 成功/失敗,之后,我的代碼可以 go 到下一行:“checkFavoriteStatus”()

但它不是那樣工作的。 即使我使用了異步等待,在我的 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 getHomepageItemsgetCarouselItems 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.

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