I'm building a score tracking app and I have a screen where you can add new players into a game. It's a simple screen that lets the user specify the player's name and color. This screen has its own ViewModel
, which I inject into the screen's composable function by using the Koin framework like this:
fun NewPlayerScreen(
viewModel: NewPlayerScreenViewModel = getViewModel(),
navController: NavHostController,
modifier: Modifier = Modifier
)
This ensures that the ViewModel
lives as long as the screen is visible on the screen. When the user clicks the "save" button on the screen, the new player gets inserted into a Room database. My problem is however, that the insertion into the database is handled by the NewPlayerScreenViewModel
. As soon as the user submits the new player, the screen exits and the ViewModel gets destroyed, which also means that its CoroutineScope
gets canceled, which means that my ongoing database operation which is inserting the player into the database might not finish properly.
I know there is one solution; I could hoist the event out of the function like this:
fun NewPlayerScreen(
viewModel: NewPlayerScreenViewModel = getViewModel(),
navController: NavHostController,
onPlayerSave: (newPlayer: Player) -> Unit,
modifier: Modifier = Modifier
)
However, this would mean, that I now have to handle the insertion into the database in another ViewModel
, in my MainScreenViewModel
, since the parent of my NewPlayerScreen()
composable is the MainScreen()
. I don't like this approach, because I'd like my screens to have their own ViewModel
s handle the database operations for themselves. Are there any other options or is this the proper way to handle this kind of situation?
CodePudding user response:
You could either:
- Wait for the insertion to happen before navigating to the next screen
You can do this by making the insertion function a suspend
function, creating a val coroutineScope = rememberCoroutineScope()
and then on the save button's onClick callback, do:
coroutineScope.launch {
viewModel.insertPlayer()
navigate()
}
Doing this, you guarantee that the operations will happend sequentially, with the drawback that the user has to wait until the player is added before navigating to the next screen.
- Schedule the work using WorkManager's
OneTimeWorkRequest