Fragments, Don’t Hurt Me
Here’s a screen I was recently working on for an app at work:
It’s built with a Fragment containing a ViewPager. Each page in the ViewPager is served by a FragmentPagerAdapter. Pretty straight forward stuff.
On first launch it works as expected, but if the enclosing Activity is destroyed, no pages get recreated by the FragmentPagerAdapter.
Here’s the code for creating the ViewPager (shortened for brevity):
And the code for the TrackerPagerAdapter (also shortened for brevity):
Can you see what’s wrong?
It turns out the issue lies with the FragmentManager passed to the TrackerPagerAdapter. If we instead pass in the Fragment’s child FragmentManager, our code works as expected.
A subtle but important difference. The FragmentManager returned by
getFragmentManager() is bound to the enclosing Activity, while
getChildFragmentManager() is tied to the Fragment itself. Since the Fragments loaded into the ViewPager are nested within our Fragment, we must use the child FragmentManager or we’ll see weird behavior like this.
We can forgo Fragments altogether by using a PagerAdapter to load views. This is how ViewPager was typically used before Fragments were introduced into the framework. If you’re looking to move away from Fragments entirely, I suggest checking out Conductor.
In our app we’ve hit similar snags with Fragments too. Issues around adding the same Fragment instance to a container, unexpected lifecycle events with the back stack when using
replace, and a handful more have arisen (dive into this r/AndroidDev thread to read about many of them).
Generally speaking, it’s not very hard to get in trouble with the Fragment APIs. Their behavior is often unexpected and this tends to compound as the complexity of your app grows.