Tag: Fragment

Programming Stuff

4 Reasons to use Android Fragments (or What Time is it?)

Although Fragments have been part of the Android API for nearly three years, I find that developers still often struggle to understand their value and purpose.

A common explanation of Fragments, and one I sometimes even use myself, is:

Fragments group user interface components and their associated logic.

That explanation is accurate. However, if someone is struggling with how to apply Fragments in a practical sense, that explanation is about as useful as teaching someone how to tell time by explaining the finer details of Swiss watch construction … sometimes you just want to know what time it is…

Read the rest of my post over on blog.pluralsight.com ]

Programming Stuff

Android Updatable Swipe Navigation with FragmentStatePagerAdapter

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.

3095_05_03

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…

  1. Select “Scrollable tabs + swipe” as the Navigation Type when generating your project in Android Studio
  2. Change the FragmentPagerAdapter base class to FragmentStatePagerAdapter
  3. Override the getItemPosition method to return POSITION_NONE
  4. 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

AndroidMindsetBanner_WithLogo

Checkout Jim’s latest book: Creating Dynamic UI with Android Fragments

Creating Dynamic UI with Fragments

Programming Stuff

Avoiding Android App Crashes Caused by Device Orientation Changes

A challenge commonly faced when first developing in Android is the potentially frequent destruction and reconstruction of an Activity. The most common time this occurs is when the user rotates the device between horizontal and portrait orientations.

Many an app that runs fine during testing suddenly crashes when put into a user’s hands simply because the user tilted the device one way or another.

This crashing usually occurs because device orientation changes cause the Android framework to tear down the displayed Activity along within any contained Views, and then to fully reconstruct the Activity/View hierarchy. Any references to the Activity or to the Views within the Activity suddenly become invalid. Similarly any references within the Activity or Views that were set as a result of a user action or similar are now lost.

There are a number of ways to deal with this issue but one of the easiest is to take advantage of Fragments.

NOTE: You can use the configChanges attribute on your Activity’s manifest entry to prevent the teardown/reconstruction process caused by orientation changes but that has its own headaches.

Fragments won’t automatically resolve this issue because, by default, when the Activity is torn-down in response to an orientation change the Fragment contained within the Activity is also torn down along with any contained Views.

The solution lies in an underused method: Fragment.setRetainInstance.

Calling setRetainInstance with a value of true causes Android to preserve the Fragment across the teardown/reconstruction cycle of an Activity. Along with the Fragment, the Views or other object references contained within the Fragment or Views remain.

With setRetainInstance(true) called on a Fragment instance … when an orientation change occurs, Android…

  1. Holds a reference to the Fragment instance
  2. Tears down the old Activity instance
  3. Creates a new Activity instance
  4. Attaches the preserved Fragment instance to the new Activity instance

With that, the Fragment, contained Views and object references, remain intact.

Something to keep in mind though … because your Fragment instance will be moved between different Activity instances, you should avoid caching a reference to the Activity. Instead call Fragment.getActivity anytime you need to reference the Activity.

Jim talks more about Fragments in his Pluralsight course…

AndroidFragments_400x100