如何在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
相关产品推荐
相关产品推荐

