Why a new ViewModel is created in each Compose Navigation route?

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:

  1. By passing it directly to viewModel call. In this case only the passed view model will be bind to parent store owner, and all other view models created inside will be bind(and so destroyed when route is removed from the stack) to current route.
  2. By proving value for LocalViewModelStoreOwner, so all composables inside will be bind to the parent view model store owner, and so are not gonna be freed when route is removed from the stack.
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>()
        }
    }
}

Leave a Comment