Android navigation component with shared view models

Muhammad Ahmed AbuTalib picture Muhammad Ahmed AbuTalib · Mar 13, 2019 · Viewed 9.4k times · Source

A viewmodel lives and dies with an activity or the fragment it is attached to. This has certain ramifications that it is beyond me why isn't anyone asking about (if we get the Navigation architecture into the picture).

According to the latest android blogs and the way navigation framework works , we are recommended to go in the Single Activity Multiple Fragments verse.

Supposedly I have the following app design .

Activity A (Application Entry Point)
----------
Fragment (A) (Uses ViewModel AB)
Fragment (B) (Uses ViewModel AB)
Fragment (C) (Uses ViewModel CDE)
Fragment (D) (Uses ViewModel CDE)
Fragment (E) (Uses ViewModel CDE)

Now since I use shared viewmodels that means my viewmodels would be attached to the activity. However this appears to be leaky. Like if I have traversed all the way from A to E and now come back popping off fragments to fragment B , the viewmodel CDE should be destroyed , but it wont be since it is connected to the activity.

Also we cannot connect our viewmodels to the fragment since we are going to be sharing their data.

The fact that only I am raising this question makes me believe i am at mistake here with my understanding. Would be elated if I could be given a proper insight into the situation.

Answer

Chenhe picture Chenhe · Jul 15, 2019

This is really a problem and has been reported to Google.

Fortunately since Navigation 2.1.0-alpha02 (stable in 2.1.0) this problem has been solved. You can find the change log here and the document.

You can now create ViewModels that are scoped at a navigation graph level via the by navGraphViewModels() property delegate for Kotlin users or by using the getViewModelStore() API added to NavController.

First you should select some of fragments in your nav graph designer, then right click on them and choice Move to Nested Graph to create a new graph which will be used as a 'scope' like this:

class DetailFr : Fragment() {
    private val vm: DetailViewModel by navGraphViewModels(R.id.main_nav_graph)
}

You can learn more about Nested Graph here.