Time for the latest in our What is… series, and the topic is Fragments.
Does it have anything to do with the so-called Android fragmentation issue? Actually, in some ways it does…
The executive summary
In a nutshell, an Activity can be thought of as a “screen-full” of content on your phone or tablet – a page, as it were, of a particular application. Think of an email application, for example, that displays the most recent emails received on the initial screen.
Well, a Fragment can be thought of as a sub-component of an Activity. It represents a portion of logic as displayed on the screen. Perhaps, for example, the index of most recent emails is one Fragment. But when you view the same app on a tablet the list of recent emails is accompanied, on the right, by the content of one particular email, previewed in its own sub-area of the screen. This could be another fragment.
Programmers are always encouraged to re-use code and always avoid, if possible, duplicating code. Fragments help serve this purpose in Android.
A self-contained unit of functionality can be implemented in a Fragment and reused in multiple places without the need for duplication. Basically, it provides a very neat way for applications to handle a variety of screen sizes and interfaces, but maintain a common codebase.
Fragments A, B, and C can be combined or separated as appropriate – perhaps changing as the user changes the orientation of the device. in landscape mode, maybe “list” and “detail” can sit side by side, but in portrait mode, only one can be displayed. Basically, it is a standardised way for Android to implement Responsive Design.
A definition of Fragment
To put it technically, in Google’s words:
A Fragment represents a behaviour or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own life-cycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a “sub activity” that you can reuse in different activities).
A fragment must always be embedded in an activity and the fragment’s life-cycle is directly affected by the host activity’s life-cycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed life-cycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that’s managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the Back button.
This takes us back to where we came in, with mention of Android fragmentation.
The “problem” of Android running on a huge variety of devices with different screen sizes becomes an opportunity for customisation and configuration.
Should you wish to address very widescreen displays, for example, you could. Should the display be very long and narrow, perhaps you can optimise your app components accordingly. In theory, the same units of code could be used.
Enter Honeycomb for tablets
Where did all begin? January 2011 saw the introduction of Android “Honeycomb” 3.0 (API level 11), which was designed from the ground up for devices with larger screen sizes such as tablets.
Part of the SDK was the Fragments API, offering developers a way to address the larger screen real-estate.
At the time, Software Engineer Dianne Hackborn wrote on the Android Developer blog:
Android 3.0 further helps applications adjust their interfaces with a new class called Fragment. A Fragment is a self-contained component with its own UI and life-cycle; it can be-reused in different parts of an application’s user interface depending on the desired UI flow for a particular device or screen.
In some ways you can think of a Fragment as a mini-Activity, though it can’t run independently but must be hosted within an actual Activity. In fact the introduction of the Fragment API gave us the opportunity to address many of the pain points we have seen developers hit with Activities.
What have Fragments ever done for Android?
So, there’s more. Over and above screen size issues, Fragments were also designed for:
- Improving handling of saving and restoring “State” data
- Making it easier to show a Dialog (as a specialised DialogFragment) that is managed as part of the Activity life-cycle
- Making it easier to show a list of data (as a specialised ListFragment)
- Retaining data across Activity instances
- Replacing “Embedded Activities” to help interact with other activities, which in themselves operate independently.
- Built-in support for managing a back-stack of Fragment objects, making it easy to provide intra-activity Back button behaviour
Fragment Life-cycle
Like an Activity – and every Fragment must be associated with an Activity, which is always accessible via the Fragment Manager – a Fragment goes through a lifecycle of events. The life-cycle is similar, but not identical, to that for an Activity.
Coding your specific app will mean hooking into (“overriding”) these standardised points of access, such as onCreate()
and onResume()
. They are called by the Android management system as it best husbands resources, which may need to be swapped in and out. The user may, for example, take calls, receive an alarm, switch to another app, etc, etc. These interruptions all have to be accommodated by the app.
Very few apps would need to access all these points, but it depends on the functionality you need to implement, and how you manage data and user interfaces across the life-cycle of your application.
The full Fragment life-cycle is pictured, right.
Less of the theory
In practice, using fragments can be fraught with a number of pitfalls.
While simple in concept, coping with multiple Fragment arrangements in code can quickly become very complex.
They are similar in life-cycle to activities, but not quite the same, which means more for the Android developer to take on board. There are now more sub-elements of the screen to manage, which adds to complexity. And, in theory, they should all be ideally coordinated, whatever the user journey and however the user may change screen orientation mid-journey.
(Remember, that a change in device orientation means that Android pauses, stops, and destroys the app and releases its resources, and then rebuilds it again afresh. All in the flick of the user’s hand.)
Add in the management of the back-stack so that fragments are stored, or not, as appropriate, and the potential need to coordinate fragment transactions, where more than one area of the screen may need to be updated in a systematic fashion, and complexity is rapidly becoming a problem…
It’s fair to say that many inter-leaved and inter-related issues surround the use of Fragments.
Also, it is possible to have basic Responsive Design by simply taking advantage of differing Android Layout files (that can be specified in advance for different screen sizes (layout-w550dp and/or layout-w750dp, for example, as well as simply layout). The Android system automatically takes care of loading the right files for the screen display (including support for changes in orientation).
This means some View elements are accessible under pre-arranged condition, and can simply be accessed directly, if conditionally (are they Null? If not, they are part of the current layout…). Of course, this doesn’t automatically support the use of Back-stack management or transaction management and other features that come with Fragments.
In code
What does it all look like in practice? You add a fragment as a part of your activity layout. Technically speaking, it lives in a ViewGroup
inside the activity’s view hierarchy and the fragment defines its own view layout.
You can insert a fragment into your activity layout by declaring the fragment in the activity’s layout file, as a <fragment> element,
or from your application code by adding it to an existing ViewGroup
. Note, however, that a fragment isn’t required to be a part of the activity layout – you may also a fragment without its own UI as an invisible support for the activity.
Here is an example of an Android layout file supporting the use of fragments
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <fragment android:name="com.example.android.fragments.HeadlinesFragment" android:id="@+id/headlines_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.android.fragments.ArticleFragment" android:id="@+id/article_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>
In code, they deal with the same standard View elements that Activities use, such as an ImageView or EditText or Button, etc. Here is some code, which handles a Fragment transaction:
// Create new fragment and transaction Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit();
Finally, there are currently 11 specialised Fragment classes, extending the Fragment
class in particular ways:
- BrowseFragment,
- DetailsFragment,
- DialogFragment,
- ErrorFragment,
- HeadersFragment,
- ListFragment,
- PreferenceFragment,
- RowsFragment,
- SearchFragment,
- VerticalGridFragment,
- WebViewFragment
Further reading
Fragments – Class guide (developer.android.com)
Building a Dynamic UI with Fragments – training (developer.android.com )