我正在构建一个分数跟踪应用程序,并且我有一个屏幕,您可以在其中将新玩家添加到游戏中。这是一个简单的屏幕,可让用户指定玩家的名称和颜色。该屏幕有自己的 ViewModel
,我通过使用 Koin 框架将其注入(inject)到屏幕的可组合函数中,如下所示:
fun NewPlayerScreen(
viewModel: NewPlayerScreenViewModel = getViewModel(),
navController: NavHostController,
modifier: Modifier = Modifier
)
这可以确保只要屏幕在屏幕上可见,ViewModel
就一直存在。当用户单击屏幕上的“保存”按钮时,新玩家将被插入到房间数据库中。然而,我的问题是,插入数据库是由 NewPlayerScreenViewModel 处理的。一旦用户提交新的播放器,屏幕就会退出,ViewModel 就会被销毁,这也意味着它的 CoroutineScope 会被取消,这意味着我正在进行的数据库操作(即将播放器插入数据库)可能无法正常完成。
我知道有一个解决方案;我可以像这样将事件从函数中提升出来:
fun NewPlayerScreen(
viewModel: NewPlayerScreenViewModel = getViewModel(),
navController: NavHostController,
onPlayerSave: (newPlayer: Player) -> Unit,
modifier: Modifier = Modifier
)
但是,这意味着我现在必须在我的 MainScreenViewModel
中的另一个 ViewModel
中处理对数据库的插入,因为我的 的父级NewPlayerScreen()
可组合项是 MainScreen()
。我不喜欢这种方法,因为我希望我的屏幕有自己的 ViewModel 来自行处理数据库操作。还有其他选择吗?或者这是处理这种情况的正确方法吗?
最佳答案
您可以:
- 等待插入发生,然后再导航到下一个屏幕
您可以通过将插入函数设置为 suspend
函数,创建 val coroutineScope = RememberCoroutineScope()
来实现此目的,然后在保存按钮的 onClick 回调上执行以下操作:
coroutineScope.launch {
viewModel.insertPlayer()
navigate()
}
这样做可以保证操作将按顺序发生,但缺点是用户必须等到添加播放器后才能导航到下一个屏幕。
- 使用 WorkManager 安排工作的
OneTimeWorkRequest
关于android - 将条目插入 Room 数据库时,ViewModelScope 可能会被取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73209284/