Android Studio makes adding swipe navigation to your Android apps easy through the “Scrollable Tabs + Swipe” option of the Navigation Type selection in the New Project Wizard. Choosing this option works great as long as you have a static list of screens that the user “swipes” between.
When Static Screen Lists Aren’t Enough
The way swipe navigation works is that each screen is represented by an instance of a Fragment-derived class. These Fragment classes are then managed by a PagerAdapter-derived class which makes them, in effect, a scrollable list. Passing that PagerAdapter to a ViewPager presents that list in a way that the user can use a swipe-motion to move between screens.
The code generated by Android Studio provides a custom PagerAdapter class that derives from  FragmentPagerAdapter. Basically all one has to do is override the getItem method and return the desired Fragment for each screen position (you’ll also need to override getCount and getPageTitle but those are super simple). What happens though is that the FragmentPagerAdapter class is designed such that once a Fragment instance is returned for a given position that Fragment is permanently in that position. Once this happens, you can, of course, make changes to the contents of the Fragment but there’s no way to provide a different Fragment instance for that position which is often what’s necessary.
The comments in the generated class indicate that using FragmentStatePagerAdapter instead of FragmentPagerAdapter as the base class allows for more dynamic management of the Fragment instances. Reading the FragmentStatePagerAdapter documentation indicates that we can notify our FragmetStatePagerAdapter instance of a change in the list of screens (in other words that we’d like to use new Fragment instances) by calling the notifyDataSetChanged method. But that’s only part of the story.
Once you call this method what you’ll normally see is that screens that were previously visited still have the old Fragment instances but screens being visited for the first time have the new Fragment instances. If you have a large number of screens and scroll back and forth between them you may see some of the older screens eventually show a new Fragment instance.
Not really the consistent user experience we’re looking for 🙂
So what’s the problem?
What’s happening is that FragmentStatePagerAdapter is trying to be efficient and only create new Fragment instances when necessary. To determine when to request new Fragment instances after a call to the notifyDataSetChanged method, FragmentStatePagerAdapter calls its getItemPosition method to see if an existing Fragment can be used in its current or possibly a different position without having to recreate it. What we have to do is tell the FragmentStatePagerAdapter instance that we don’t want to use the existing Fragment instance.
To do that we need to override getItemPosition as follows
public int getItemPosition(Object object) { // Causes adapter to reload all Fragments when // notifyDataSetChanged is called return POSITION_NONE; }
By returning POSITION_NONE we’re telling the FragmentStatePagerAdapter instance to discard that Fragment and just create new ones for every screen position.
Summary: How To Create Updatable Swipe Navigation
To summarize what to do, here’s the list of steps…
- Select “Scrollable tabs + swipe” as the Navigation Type when generating your project in Android Studio
- Change the FragmentPagerAdapter base class to FragmentStatePagerAdapter
- Override the getItemPosition method to return POSITION_NONE
- Call notifyDataSetChanged in your code when you’d like to load new Fragment instances.
And with that, you have the ease of swipe navigation with the ability to reload Fragments instances as needed
Adapted from Jim’s Pluralsight course Android for .NET Developers: Adopting the Android Mindset
Checkout Jim’s latest book: Creating Dynamic UI with Android Fragments