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

如何等待viewModelScope.launch执行完成后再进行页面导航?

解决Room数据库保存未完成就跳转导致数据丢失的问题

问题根源

你当前的代码中,deleteAllPlayerRecords()、savePlayersRecord()、saveScoreCardRecord()内部通过viewModelScope.launch启动异步协程执行数据库操作,但这些协程不会阻塞onSaveSelection()的执行。点击按钮后,onSaveSelection()立刻返回并触发页面跳转,当前页面的ViewModel可能被销毁,viewModelScope会取消所有未完成的协程,导致数据库操作中断,数据保存不完整。

解决方案

核心思路是等待所有数据库操作完成后再执行页面跳转,具体步骤如下:

1. 将ViewModel中的数据库操作改为挂起函数

Room的DAO方法原生支持挂起(用suspend修饰),调用挂起方法会自动在后台线程执行,并阻塞当前协程直到操作完成。需要把原来启动协程的方法改成直接调用挂起DAO方法的挂起函数:

// ViewModel中的代码修改
suspend fun deleteAllPlayerRecords() {
    // 直接调用DAO的挂起删除方法
    playerDao.deleteAll()
}

suspend fun savePlayersRecord() {
    // 循环保存玩家数据,调用DAO的挂起插入方法
    players.forEach { player ->
        playerDao.insert(player)
    }
}

suspend fun saveScoreCardRecord() {
    // 调用DAO的挂起插入方法保存计分卡
    scoreCardDao.insert(scoreCard)
}

// 统一执行所有保存操作的挂起函数
suspend fun saveAllRecords() {
    // 顺序执行三个操作,全部完成后才会返回
    deleteAllPlayerRecords()
    savePlayersRecord()
    saveScoreCardRecord()
}

2. 在UI点击事件中等待保存完成再跳转

在Compose中,点击事件是普通函数无法直接挂起,需要用rememberCoroutineScope创建与组件生命周期绑定的协程作用域,在协程内先执行保存操作,完成后再跳转:

// UI层的点击事件修改
val coroutineScope = rememberCoroutineScope()

onClick = {
    coroutineScope.launch {
        try {
            // 等待所有保存操作完成
            viewModel.saveAllRecords()
            // 保存完成后再跳转页面
            navHostController.navigate(Screen.ScoreCard.route)
        } catch (e: Exception) {
            // 处理保存失败的情况,比如打印日志或提示用户
            Log.e("SaveError", "保存数据失败", e)
            // 可添加Snackbar/Toast提示用户保存失败
        }
    }
}

关键说明

  • 挂起函数确保数据库操作顺序执行且全部完成,避免异步协程被ViewModel销毁中断。
  • rememberCoroutineScope的作用域与当前Compose组件绑定,会在组件销毁时取消协程,但由于我们先等待保存完成再跳转,此时操作已执行完毕,不会出现数据丢失。
  • 必须确保Room DAO中的对应方法都用suspend修饰,否则无法实现挂起等待。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:42:39