How do I preserve ViewModel in nested Fragments inside ViewPager2

Viewed 131

I have an app with a RootFragment containing a ViewPager2, presenting multiple ChildFragment.

The RootFragment has a RootViewModel, and each ChildFragment also has a ChildViewModel.

Running the app, I can see that the root fragment's view model is being created once and preserved through rotations etc - this is exactly what I expected to happen.

However, when I scroll through the child fragments and back again it looks like the ChildVieWModels are being recreated each time the ViewPager2 destroys/recreates the fragments to display. This isn't what I need at all!

How can I get the view models of the child fragment to remain even though the child fragments themselves are being destroyed and recreated by the ViewPager2?

My child fragment is requesting a view model like this:

private val viewModel: ChildViewModel by viewModels()

I have also tried scoping the child view model to the parent fragment but that just means each child fragment gets the same instance of ChildViewModel, which isn't quite right either:

private val viewModel: ChildViewModel by viewModels({ requireParentFragment() })

I've looked at the samples for ViewPager2 but none of them seem to have a view model in their child fragments.

What have I misunderstood here?

1 Answers

How can I get the view models of the child fragment to remain even though the child fragments themselves are being destroyed and recreated by the ViewPager2?

You could set the offscreen page limit. See doc https://developer.android.com/reference/androidx/viewpager2/widget/ViewPager2#setOffscreenPageLimit(int)

If you set the limit to 2, then the fragments that will be kept alive are the current tab, the next 2 tabs and the previous 2 tabs in the viewpager. You can use this to keep all fragments and viewmodels in the viewpager alive if the number of tabs/childfragments are static and small, for example 5 or less.

If the child fragments have some shared state among them or some expensive queries in child fragments, then you can put that in the RootViewModel and use that in your child fragments by doing requireParentFragment as you have pointed out.

There really isn't a better way than to set the offscreen limit or sharing the viewmodel with the parent fragment.

Related