Why a new ViewModel is created in each Compose Navigation route?
I have a single activity app using only composables for the ui (one activity, no fragments). I use one viewmodel to keep data for the ui in two different screens (composables). I create the viewmodel in both screens as described in state documentation
@Composable
fun HelloScreen(helloViewModel: HelloViewModel = viewModel())
Now I noticed that the data that was loaded or set in the first screen is reset in the second.
I also noticed that init{}
is called every time viewModel()
is called. Is this really the expected behavior?
According to the method's documentation it should return either an existing ViewModel or create a new one.
I also see that the view models are different objects. So viewModel()
always creates a new one. But why?
Any ideas what I could be doing wrong? Or do I misunderstand the usage of the method?
Solution 1:
Usually view model is shared for the whole composables scope, and init
shouldn't be called more than once.
But if you're using compose navigation, it creates a new model store owner for each destination. If you need to share models between destination, you can do it like in two ways:
- By passing it directly to
viewModel
call - By proving value for
LocalViewModelStoreOwner
, so all composables inside will have access to the same view model store owner.
val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
"No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
}
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "first") {
composable("first") {
val model = viewModel<Model>(viewModelStoreOwner = viewModelStoreOwner)
}
composable("second") {
CompositionLocalProvider(
LocalViewModelStoreOwner provides viewModelStoreOwner
) {
val model = viewModel<Model>()
}
}
}