Kotlin+Jetpack Compose:点击Done按钮多次才能向Room数据库插入数据
Room数据库需多次点击才插入数据的问题排查与修复
问题核心原因
你的问题出在状态更新的时序异步性:在点击事件中连续调用setNoOfQuestions、setQuestionsSolved、upsertQuestionsSolved时,ViewModel的uiState状态更新不会立即同步。导致:
- 调用
setQuestionsSolved时,uiState.noOfQuestions还是旧值,并未使用刚传入的it - 最终
upsert的uiState.questionsSolved是未更新的无效数据 - 多次点击后状态逐步同步,直到第三次才凑齐正确数据完成插入
修复方案
将状态更新与数据库插入逻辑合并到ViewModel内部,避免在外部依赖未同步的uiState值:
1. 在ViewModel中新增统一处理函数
fun onDoneClicked(newNoOfQuestions: Int) { viewModelScope.launch { // 1. 更新UI状态中的题目数量 _uiState.update { currentState -> currentState.copy(noOfQuestions = newNoOfQuestions) } // 2. 创建/更新要插入的QuestionsSolved对象(直接用最新状态值) val updatedData = uiState.value.questionsSolved.copy( date = uiState.value.date, noOfQuestions = newNoOfQuestions ) // 3. 执行数据库插入 dao.upsertQuestionsSolved(updatedData) // 4. 更新UI状态中的questionsSolved _uiState.update { currentState -> currentState.copy(questionsSolved = updatedData) } } }
(注:若你使用mutableStateOf而非MutableStateFlow,将_uiState.update改为直接赋值即可)
2. 简化Done按钮的点击逻辑
Button( onClick = { viewModel.onDoneClicked(textState.toInt()) } ) { Text(text = "Done") }
3. 移除分散的状态调用
删除原点击事件中的setNoOfQuestions、setQuestionsSolved、upsertQuestionsSolved独立调用,所有逻辑通过onDoneClicked统一处理,确保每一步都使用最新状态值。
额外检查点
- 确认
QuestionsSolved的主键配置:若@Upsert的主键值(比如日期)未变化,Room会执行更新而非插入,可能造成“未插入”的错觉 - 若使用
mutableStateOf,确保状态更新在viewModelScope内执行,保证线程安全
内容的提问来源于stack exchange,提问作者Chitin
相关产品推荐
相关产品推荐

