You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中让图片保存与导航异步操作按顺序执行?

问题原因

你用async/await没达到预期顺序的核心问题是:被async包裹的函数只是启动了内部协程,没有等待内部异步操作完成就立即返回。

比如:

  • saveProfilePhoto内部用launchIn(viewModelScope)启动了收集流的协程,但函数本身会瞬间执行完返回,savePhotoToService.await()根本等不到服务端保存完成就继续往下走;
  • saveUserImgToDataStore和navigate同理,内部的viewModelScope.launch都是立即启动新协程并返回原函数,导致await()无法等待真正的异步任务结束。

这就造成了导航操作先执行(输出3),而服务端保存的回调(输出1)和本地保存完成的逻辑(输出2)滞后执行,出现1、3、2的顺序。

解决方案

把这些函数改成挂起函数,让它们内部的异步操作完成后才返回,这样async/await或者直接在协程中顺序调用就能保证执行顺序。

修改后的代码示例

1. 保存到DataStore(改为挂起函数)

private suspend fun saveUserImgToDataStore(
    userAvatar: String,
    navHostController: NavHostController,
    route: String
) {
    try {
        dataStore.putPreference(PreferenceDataStoreConstants.USER_IMG, userAvatar)
        println("2") // 本地保存完成的标记
    } catch (e: Exception) {
        Log.e("error", e.toString())
        navHostController.navigate(route)
    }
}

2. 保存到服务端(改为挂起函数)

private suspend fun saveProfilePhoto(encodedImg: String?) {
    if (!encodedImg.isNullOrEmpty()) {
        val _encodedImg = "data:image/png;base64,$encodedImg"
        saveProfilePhotoUseCase.invoke(SaveProfilePhotoRequestModel(_encodedImg))
            .collect { 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
                            )
                        }
                    }
                }
            }
    }
}

3. 导航函数(改为挂起函数)

private suspend fun navigate(navHostController: NavHostController, route: String) {
    navHostController.navigate(route)
    println("3")
}

4. 执行保存并导航(两种方式可选)

如果需要先服务端保存,再本地保存,最后导航,直接顺序调用:

fun saveImageAndNavigate(
    encodedImg: String?,
    capturedImageUri: String,
    navHostController: NavHostController,
    route: String
) {
    viewModelScope.launch {
        saveProfilePhoto(encodedImg)
        saveUserImgToDataStore(capturedImageUri, navHostController, route)
        navigate(navHostController, route)
    }
}

如果想并行执行服务端和本地保存,完成后再导航,用async/await并行:

fun saveImageAndNavigate(
    encodedImg: String?,
    capturedImageUri: String,
    navHostController: NavHostController,
    route: String
) {
    viewModelScope.launch {
        val saveServiceJob = async { saveProfilePhoto(encodedImg) }
        val saveLocalJob = async { saveUserImgToDataStore(capturedImageUri, navHostController, route) }
        
        // 等待两个保存任务都完成
        saveServiceJob.await()
        saveLocalJob.await()
        
        // 执行导航
        navigate(navHostController, route)
    }
}

这样就能保证所有保存操作完成后才执行导航,输出顺序会符合预期的1、2、3。

内容的提问来源于stack exchange,提问作者NewPartizal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:19:58