Sharing ViewModel of a nav destination with another nav destination
We can share view model of parent fragment with child fragment or with all destinations of a graph. But we must make sure that the parent fragment will have a stored view model when we access it, that is, we must make sure that the parent fragment will be in the back entry queue.
How view model is created and accessed with viewModels() delegate?
When you create lazy delegate with:private val viewModel : MyViewModel by viewModels()
Or:
private val viewModel by lazy {
ViewModelProvider(this).get(MyViewModel::class.java)
}
When you call this, you call Fragment.createViewModelLazy() from FragmentViewModelLazy. This, in its turn, creates a instance of ViewModelLazy (child class of ViewModelProvider) with the value property, that when accessed creates a view model or return a cached view model.
FragmentManager has a queue called back stack with the fragments accessed by the user. This back stack stores BackStackEntry objects, that is a tuple of SavedState, ViewModelStore and other objects. When you create a view model for a fragment with the delegate, its ViewModelStore is passed to ViewModelProvider (called by delegate, accessed via its child class ViewModelLazy) to store the view models (one per class name of view model) of this fragment.
As back entry wasn't destroy when configuration changes, the ViewModelStore is preserved with all its view models. When the fragment is popped off the back stack, its lifecycle will be destroyed, state will no longer be saved, and view models will be cleared.
How view model is created and accessed with navGraphViewModels() delegate?
When you create lazy delegate with:
//for a graph with file resource
val viewmodel: MainViewModel by navGraphViewModels(R.navigation.main) Or:
//for a graph without file resource
val viewmodel: MainViewModel by navGraphViewModels(R.id.mainNavigation)
When you call this, you call Fragment.navGraphViewModels() from NavGraphViewModelLazy returning a Lazy<VM>. This, in its turn, call Fragment.createViewModelLazy() from FragmentViewModelLazy, which creates a instance of ViewModelLazy (nested class of ViewModelProvider) with the value property, that when accessed creates a view model or return a cached view model.
NavController has a queue called back stack with the destinations accessed by the user. This back stack stores NavBackStackEntry, that is a tuple of SavedState, ViewModelStore and other objects. When you create a view model for a graph or nested graph with the delegate, this ViewModelStore is passed to ViewModelProvider (called by delegate and accessed from its ViewModelLazy nested class) to store the view models (one per class name of view model) of this graph.
As back entry wasn't destroy when configuration changes, the ViewModelStore is preserved with all its view models. When all destinations of the graph is popped off the back stack, its lifecycle will be destroyed, state will no longer be saved, and view models will be cleared.
A problem can occur with navigation drawer, because this has unrelated initial destinations. If you associate a view model with one of the initial destinations but that is not the graph's initial destination, the children of this initial destination will not be able to access their parent's view model, as the parent is deleted from the back entry. A solution to this possible problem is to associate the view model to the graph and not to the graph's home destination.