如何在 kotlin 中正确顺序运行异步操作?

问题描述 投票:0回答:1

我正在保存照片。用户拍摄照片或从图库中选择照片,然后将请求发送到服务并保存到区域设置。当然,这些都是异步完成的,在保存过程之后,他必须再次导航回个人资料页面。我使用了async wait来分别管理这些操作,因为有时直接导航图像而不保存,导致图像不显示。所以我就走了这样的路

将图像保存到数据存储

 private fun saveUserImgToDataStore(
        userAvatar: String,
        navHostController: NavHostController,
        route: String
    ) {

        viewModelScope.launch {
            try {
                dataStore.putPreference(PreferenceDataStoreConstants.USER_IMG, userAvatar)
            } catch (e: Exception) {
                Log.e("error", e.toString())
                navHostController.navigate(route)
            }
        }
    }

将照片保存到服务

private fun saveProfilePhoto(encodedImg: String?) {


    if (!encodedImg.isNullOrEmpty()) {
        val _encodedImg = "data:image/png;base64,$encodedImg"
        saveProfilePhotoUseCase.invoke(SaveProfilePhotoRequestModel(_encodedImg))
            .onEach { result ->
                println("1")
                when (result) {
                    is Resource.Success -> {
                        _state.update {
                            it.copy(
                                isLoadingSavePhoto = false,
                                responseSavePhoto = result.data,
                                isError = result.data?.isError == 1
                            )
                        }

                    }
                    is Resource.Loading -> {
                        _state.update {
                            it.copy(
                                isLoadingSavePhoto = true
                            )
                        }
                    }
                    is Resource.Error -> {
                        _state.update {
                            it.copy(
                                error = !result.message.isNullOrEmpty(),
                                isLoadingSavePhoto = false
                            )
                        }
                    }
                }
            }.launchIn(viewModelScope)
    }
}

保存图像并导航

 fun saveImageAndNavigate(
        encodedImg: String?,
        capturedImageUri: String,
        navHostController: NavHostController,
        route: String
    ){

        viewModelScope.launch {
            val savePhotoToService = async { saveProfilePhoto(encodedImg) }
            val savePhotoToLocale = async { saveUserImgToDataStore(capturedImageUri, navHostController, route) }
            val navigate = async { navigate(navHostController, route) }

            savePhotoToService.await()
            savePhotoToLocale.await()
            navigate.await()
        }
    }

导航

 private fun navigate(navHostController: NavHostController, route: String) {

        viewModelScope.launch {
            navHostController.navigate(route)
            println("3")
        }

    }

但是即使我使用了异步等待它也不起作用。正如你所看到的,我用 println() 在屏幕上显示了它们的顺序,虽然通常应该按照 1 2 3 的顺序写入,但它却像 1 3 2 一样乱序写入。我怎样才能让它们等待彼此?

kotlin asynchronous async-await
1个回答
0
投票

你的代码和你的问题标题有同样的混乱。异步和顺序是相反的。你不能同时做这两件事!理论上,您可以启动异步工作,然后等待它同步完成,但这毫无意义。

当您启动协程时,从调用它的代码的角度来看,协程是异步运行的。

挂起函数是同步函数,能够在与调用该函数的代码不同的适当线程上运行长时间运行的代码。

既然你想要顺序行为,你应该定义同步挂起函数,而不是异步函数(那些通过

launch
调用触发其他协程的函数),并且你不应该将函数调用包装在
async
块中,从而使它们“甚至更多”异步。

例如,这个函数应该重写如下:

private suspend fun saveUserImgToDataStore(
        userAvatar: String,
        navHostController: NavHostController,
        route: String
) {
    try {
        dataStore.putPreference(PreferenceDataStoreConstants.USER_IMG, userAvatar)
    } catch (e: Exception) {
         Log.e("error", e.toString())
         navHostController.navigate(route)
    }
}

你的第二个功能令人困惑,因为我不明白在保存单张照片的过程中消耗整个流程有什么意义。所以需要一些设计工作。

但是当你完成将这些函数修复为不启动其他协程的挂起函数后,调用它们的代码就可以简单地按顺序调用它们:

fun saveImageAndNavigate(
    encodedImg: String?,
    capturedImageUri: String,
    navHostController: NavHostController,
    route: String
){
    viewModelScope.launch {
        saveProfilePhoto(encodedImg)
        saveUserImgToDataStore(capturedImageUri, navHostController, route)
        navigate(navHostController, route)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.