繁体   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