Manually clearing an Android ViewModel?

Quick solution without having to use Navigation Component library:

getActivity().getViewModelStore().clear();

This will solve this problem without incorporating the Navigation Component library. It’s also a simple one line of code. It will clear out those ViewModels that are shared between Fragments via the Activity


If you check the code here you'll find out, that you can get the ViewModelStore from a ViewModelStoreOwner and Fragment, FragmentActivity for example implements, that interface.

Soo from there you could just call viewModelStore.clear(), which as the documentation says:

 /**
 *  Clears internal storage and notifies ViewModels that they are no longer used.
 */
public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
}

N.B.: This will clear all the available ViewModels for the specific LifeCycleOwner, this does not allow you to clear one specific ViewModel.


I think I have a better solution.

As stated by @Nagy Robi, you could clear the ViewModel by call viewModelStore.clear(). The problem with this is that it will clear ALL the view model scoped within this ViewModelStore. In other words, you won't have control of which ViewModel to clear.

But according to @mikehc here. We could actually create our very own ViewModelStore instead. This will allow us granular control to what scope the ViewModel have to exist.

Note: I have not seen anyone do this approach but I hope this is a valid one. This will be a really good way to control scopes in a Single Activity Application.

Please give some feedbacks on this approach. Anything will be appreciated.

Update:

Since Navigation Component v2.1.0-alpha02, ViewModels could now be scoped to a flow. The downside to this is that you have to implement Navigation Component to your project and also you have no granualar control to the scope of your ViewModel. But this seems to be a better thing.


As OP and Archie said, Google has given us the ability to scope ViewModel to navigation graphs. I will add how to do it here if you are using the navigation component already.

You can select all the fragments that needs to be grouped together inside the nav graph and right-click->move to nested graph->new graph

now this will move the selected fragments to a nested graph inside the main nav graph like this:

<navigation app:startDestination="@id/homeFragment" ...>
    <fragment android:id="@+id/homeFragment" .../>
    <fragment android:id="@+id/productListFragment" .../>
    <fragment android:id="@+id/productFragment" .../>
    <fragment android:id="@+id/bargainFragment" .../>

    <navigation 
        android:id="@+id/checkout_graph" 
        app:startDestination="@id/cartFragment">

        <fragment android:id="@+id/orderSummaryFragment".../>
        <fragment android:id="@+id/addressFragment" .../>
        <fragment android:id="@+id/paymentFragment" .../>
        <fragment android:id="@+id/cartFragment" .../>

    </navigation>

</navigation>

Now, inside the fragments when you initialise the viewmodel do this

val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph)

if you need to pass the viewmodel factory(may be for injecting the viewmodel) you can do it like this:

val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph) { viewModelFactory }

Make sure its R.id.checkout_graph and not R.navigation.checkout_graph

For some reason creating the nav graph and using include to nest it inside the main nav graph was not working for me. Probably is a bug.

Source: https://medium.com/androiddevelopers/viewmodels-with-saved-state-jetpack-navigation-data-binding-and-coroutines-df476b78144e

Thanks, OP and @Archie for pointing me in the right direction.