Traditionally, each screen within an Android application was tied to a specific Activity
class. However, in Android 3.0 (Honeycomb), the concept of a Fragment
was introduced. Fragments were then included in the Android Support Library for use with Android 1.6 (API Level 4) and up. Fragments decouple user interface components or behaviors (without a user interface) from a specific Activity
lifecycle. Instead, Activity
classes can mix and match user interface components or behaviors to create more flexible user interfaces. This chapter explains what fragments are and how you can use them. We also introduce the concept of nested fragments.
Fragments were added to the Android SDK at a crucial time when consumers were experiencing an explosion in the variety of Android devices coming to market. We now see not just smartphones but other larger-screen devices such as tablets and televisions that run the platform. These larger devices come with substantially more screen real estate for developers to take advantage of. Your typical streamlined and elegant smartphone user interface often looks oversimplified on a tablet, for example. By incorporating Fragment
components into your user interface design, you can write one application that can be tailored to these different screen characteristics and orientations instead of different applications tailored for different types of devices. This greatly improves code reuse, simplifies application testing needs, and makes publication and application package management much less cumbersome.
As we stated in the introduction to this chapter, the basic rule of thumb for developing Android applications used to be to have one Activity
per screen of an application. This ties the underlying “task” functionality of an Activity
class very directly to the user interface. However, as bigger device screens came along, this technique faced some issues. When you had more room on a single screen to do more, you had to implement separate Activity
classes, with very similar functionality, to handle the cases where you wanted to provide more functionality on a given screen. Fragments help manage this problem by encapsulating screen functionality into reusable components that can be mixed and matched within Activity
classes.
Let’s look at a theoretical example. Say you have a traditional smartphone application with two screens. Perhaps it’s an online news-journal application. The first screen contains a ListActivity
with a ListView
control. Each item in the ListView
represents an article available from the journal that you might want to read. When you click a specific article, since this is an online news-journal application, you are sent to a new screen that displays the article contents in a WebView
control. This traditional screen workflow is illustrated in Figure 9.1.
This workflow works fine for small-screen smartphones, but it’s a waste of all the space on a tablet or a television. Here, you might want to be able to peruse the article list and preview or read the article on the same screen. If we organize the ListView
and the WebView
screen functionality into two stand-alone Fragment
components, we can easily create a layout that includes both on the same screen when screen real estate allows, as shown in Figure 9.2.
We discussed the Activity
lifecycle back in Chapter 4, “Understanding Application Components.” Now let’s look at how a Fragment
fits into the mix. First of all, a Fragment
must be hosted within an Activity
class. It has its own lifecycle, but it is not a stand-alone component that can exist outside the context of an Activity
.
The responsibilities of Activity
class management are greatly simplified when the entire user interface state is moved off into individual fragments. Activity
classes with only fragments in their layouts no longer need to spend a lot of time saving and restoring their state because the Activity
object now keeps track of any Fragment
that is currently attached automatically. The Fragment
components themselves keep track of their own state using their own lifecycle. Naturally, you can mix fragments with View
controls directly in an Activity
class. The Activity
class will be responsible for managing the View
controls, as normal.
The Activity
must focus on managing its Fragment
classes. Coordination between an Activity
and its Fragment
components is facilitated by the FragmentManager
(android.app.FragmentManager
). The FragmentManager
is acquired from the getFragmentManager()
method, which is available within the Activity
and Fragment
classes. When using the support library, coordinatiocn is facilitated by the FragmentManager
(android.support.v4.app.FragmentManager
) and is acquired from the getSupportFragmentManager()
method of the FragmentActivity
support APIs.
Fragment
implementations that have been defined as regular classes within your application can be added to your layout resource files by using the <fragment>
XML tag and then loaded into your Activity
using the standard setContentView()
method, which is normally called in the onCreate()
method of your Activity
.
When you reference a Fragment
class that you have defined in your application package in an XML layout file, use the <fragment>
tag. This tag has a few important attributes. Specifically, you will need to set the android:name
attribute of the fragment to the fully qualified Fragment
class name. You will also need to give the item a unique identifier using the android:id
attribute so that you can access that component programmatically, if needed. You still need to set the component’s layout_width
and layout_height
attributes as you would for any other control in your layout. Here is a simple example of a <fragment>
layout reference that refers to a class called VeggieGardenListFragment
, which is defined as a .java
class in the package:
<fragment
android:name="com.introtoandroid.simplefragments.VeggieGardenListFragment"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
As you can see, when you have multiple Fragment
components on a single screen, within a single Activity
, user interaction on one Fragment
(such as our news ListView Fragment
) often causes the Activity
to update another Fragment
(such as our article WebView Fragment
). An update or modification to a Fragment
is performed using a FragmentTransaction
(android.app.FragmentTransaction
or android.support.v4.app.FragmentTransaction
). A number of different actions can be applied to a Fragment
using a FragmentTransaction
operation, such as the following:
A Fragment
can be attached or reattached to the parent Activity
.
A Fragment
can be hidden and unhidden from view.
Perhaps at this point you are wondering how the Back
button fits into the Fragment
-based user interface design. Well, now the parent Activity
class has its own back stack. As the developer, you can decide which FragmentTransaction
operations are worth storing in the back stack and which are not by using the addToBackStack()
method of the FragmentTransaction
object. For example, in our news application example, we might want each of the articles displayed in the WebView Fragment
to be added to the parent Activity
class’s back stack so that if the user hits the Back
button, he or she traverses the articles already read before backing out of the Activity
entirely.
After you have a Fragment
that you want to include within your Activity
class, the lifecycle of the Fragment
comes into play. The following callback methods are important to managing the lifecycle of a Fragment
, as it is created and then destroyed when it is no longer used. Many of these lifecycle events mirror those in the Activity
lifecycle:
The onAttach()
callback method is called when a Fragment
is first attached to a specific Activity
class.
The onCreate()
callback method is called when a Fragment
is first being created.
The onCreateView()
callback method is called when the user interface layout, or View
hierarchy, associated with the Fragment
should be created.
The onActivityCreated()
callback method will inform the Fragment
when its parent Activity
class’s onCreate()
method has completed.
The onStart()
callback method is called when the Fragment
’s user interface becomes visible but is not yet active.
The onResume()
callback method makes the Fragment
’s user interface active for interaction after the Activity
has resumed or the Fragment
was updated using a FragmentTransaction
.
The onPause()
callback method is called when the parent Activity
is paused, or the Fragment
is being updated by a FragmentTransaction
. It indicates that the Fragment
is no longer active or in the foreground.
The onStop()
callback method is called when the parent Activity
is stopped, or the Fragment
is being updated by a FragmentTransaction
. It indicates the Fragment
is no longer visible.
The onDestroyView()
callback method is called to clean up any user interface layout, or View
hierarchy resources, associated with the Fragment
.
The onDestroy()
callback method is called to clean up any other resources associated with the Fragment
.
The onDetach()
callback method is called just before the Fragment
is detached from the Activity
class.
Recall from Chapter 8, “Positioning with Layouts,” that there are a number of special Activity
classes for managing certain common types of user interfaces. For example, the ListActivity
class simplifies the creation of an Activity
that manages a ListView
control. Similarly, the PreferenceActivity
class simplifies the creation of an Activity
to manage shared preferences. And as we saw in our news reader application example, we often want to use user interface controls such as ListView
and WebView
within our Fragment
components.
Because fragments are meant to decouple this functionality from the Activity
class, you’ll now find equivalent Fragment
subclasses that perform this functionality instead. Some of the specialty Fragment
classes you’ll want to familiarize yourself with include the following:
ListFragment (android.app.ListFragment): Much like a ListActivity
, this Fragment
class hosts a ListView
control.
PreferenceFragment (android.preference.PreferenceFragment): Much like a PreferenceActivity
, this Fragment
class lets you easily manage user preferences.
WebViewFragment (android.webkit.WebViewFragment): This type of Fragment
hosts a WebView
control to easily render Web content. Your application will still need the android.permission.INTERNET
permission to access the Internet.
DialogFragment (android.app.DialogFragment): Decoupling user interface functionality from your Activity
classes means you won’t want your dialogs managed by the Activity
either. Instead, you can use this class to host and manage Dialog
controls as fragments. Dialogs can be traditional pop-ups or embedded. We discuss dialogs in Chapter 10, “Architecting with Patterns.”
Note
For a complete list of the different types of special fragments, see the Fragment
reference documentation and look for the different subclasses available here: http://d.android.com/reference/android/app/Fragment.html.
At the end of the day, Fragment
-based applications are best learned by example. Therefore, let’s work through a fairly straightforward example to help nail down the many concepts we have discussed thus far in the chapter. To keep things simple, we will target a specific version of the Android platform: Android Marshmallow. However, you will soon find that you can also create Fragment
-based applications for almost any device by using the Android Support Package.
Tip
Many of the code examples provided in this section are taken from the SimpleFragments
application. The source code for the SimpleFragments
application is provided for download on the book’s website (http://introductiontoandroid.blogspot.com).
Andy (a fictitious robot) is a fan of gardening and has many fruits and vegetables growing in his garden. Let’s make a simple application with a ListView
of fruit and vegetable names. Clicking a ListView
item will load a WebView
control and display a specific webpage associated with that fruit or vegetable. To keep things simple, we’ll store our fruit and vegetable list, and Web-page URLs in string array resources. (See the sample code provided for download on this book’s website for a complete implementation.)
So how will our fragments work? We will use a ListFragment
for the fruit and vegetable list, and a WebViewFragment
to display each associated Web page. In portrait mode, we will display one fragment per screen, requiring two Activity
classes, as shown in Figure 9.3. In this sample, we will be using the AppCompatActivity
class (android.support.v7.app.AppCompatActivity
).
In landscape mode, we will display both fragments on the same screen within the same AppCompatActivity
class, as shown in Figure 9.4.
Let’s begin by defining a custom ListFragment
class called VeggieGardenListFragment
to host our fruit and vegetable names. This class will need to determine whether the second Fragment
, the VeggieGardenWebViewFragment
, should be loaded or if ListView
clicks should simply cause the VeggieGardenViewActivity
to be launched:
public class VeggieGardenListFragment extends ListFragment implements
FragmentManager.OnBackStackChangedListener {
private static final String DEBUG_TAG = "VeggieGardenListFragment";
int mCurPosition = 1;
boolean mShowTwoFragments;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
String[] veggies = getResources().getStringArray(
R.array.veggies_array);
setListAdapter(new ArrayAdapter<>(getActivity(),
android.R.layout.simple_list_item_activated_1, veggies));
View detailsFrame = getActivity().findViewById(R.id.veggieentry);
mShowTwoFragments = detailsFrame != null
&& detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
mCurPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mShowTwoFragments == true || mCurPosition != 1) {
viewVeggieInfo(mCurPosition);
}
getFragmentManager().addOnBackStackChangedListener(this);
}
@Override
public void onBackStackChanged() {
VeggieGardenWebViewFragment details =
(VeggieGardenWebViewFragment) getFragmentManager()
.findFragmentById(R.id.veggieentry);
if (details != null) {
mCurPosition = details.getShownIndex();
getListView().setItemChecked(mCurPosition, true);
if (!mShowTwoFragments) {
viewVeggieInfo(mCurPosition);
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurPosition);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
viewVeggieInfo(position);
}
void viewVeggieInfo(int index) {
mCurPosition = index;
if (mShowTwoFragments == true) {
// Check what fragment is currently shown, replace if needed.
VeggieGardenWebViewFragment details =
(VeggieGardenWebViewFragment) getFragmentManager()
.findFragmentById(R.id.veggieentry);
if (details == null || details.getShownIndex() != index) {
VeggieGardenWebViewFragment newDetails = VeggieGardenWebViewFragment
.newInstance(index);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.veggieentry, newDetails);
if (index != 1) {
String[] veggies = getResources().getStringArray(
R.array.veggies_array);
String strBackStackTagName = veggies[index];
ft.addToBackStack(strBackStackTagName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
Intent intent = new Intent();
intent.setClass(getActivity(), VeggieGardenViewActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
Most of the Fragment
control’s initialization happens in the onActivityCreated()
callback method so that we initialize the ListView
only once. We then check to see which display mode we want to be in by checking to see if our second component is defined in the layout. Finally, we leave the display details to the helper method called viewVeggieInfo()
, which is also called whenever an item in the ListView
control is clicked.
The logic for the viewVeggieInfo()
method takes into account both display modes. If the device is in portrait mode, the VeggieGardenViewActivity
is launched via Intent
. However, if the device is in landscape mode, we have some Fragment
finagling to do.
Specifically, the FragmentManager
is used to find the existing VeggieGardenWebViewFragment
by its unique identifier (R.id.veggieentry
, as defined in the layout resource file). Then, a new VeggieGardenWebViewFragment
instance is created for the new fruit or vegetable Web page being requested. Next, a FragmentTransaction
is started, in which the existing VeggieGardenWebViewFragment
is replaced with the new one. We put the old one on the back stack so that the Back
button works nicely, set the transition animation to fade between the blog entries, and commit the transaction, thus causing the screen to update asynchronously.
Finally, we can monitor the back stack with a call to the addOnBackStackChangedListener()
method. The callback onBackStackChanged()
updates the list to the current selected item. This provides a robust way to keep the ListView
item selection synchronized with the currently displayed Fragment
both when adding a new Fragment
to the back stack and when removing one, such as when the user presses the Back
button.
Next, we create a custom WebViewFragment
class called VeggieGardenWebViewFragment
to host the webpage related to each fruit or vegetable. This Fragment
class does little more than determine which Web page URL to load and then load it in the WebView
control:
public class VeggieGardenWebViewFragment extends WebViewFragment {
private static final String DEBUG_TAG = "VGWebViewFragment";
public static VeggieGardenWebViewFragment newInstance(int index) {
Log.v(DEBUG_TAG, "Creating new instance: " + index);
VeggieGardenWebViewFragment fragment =
new VeggieGardenWebViewFragment();
Bundle args = new Bundle();
args.putInt("index", index);
fragment.setArguments(args);
return fragment;
}
public int getShownIndex() {
int index = 1;
Bundle args = getArguments();
if (args != null) {
index = args.getInt("index", −1);
}
if (index == −1) {
Log.e(DEBUG_TAG, "Not an array index.");
}
return index;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] veggieUrls = getResources().getStringArray(
R.array.veggieurls_array);
int veggieUrlIndex = getShownIndex();
WebView webview = getWebView();
webview.setPadding(0, 0, 0, 0);
webview.getSettings().setLoadWithOverviewMode(true);
webview.getSettings().setUseWideViewPort(true);
if (veggieUrlIndex != 1) {
String veggieUrl = veggieUrls[veggieUrlIndex];
webview.loadUrl(veggieUrl);
} else {
String veggieUrl = "http://andys-veggie-garden." +
"appspot.com/cherrytomatoes";
webview.loadUrl(veggieUrl);
}
}
}
Most of the Fragment
control’s initialization happens in the onActivityCreated()
callback method so that we initialize the WebView
only once. The default configuration of the WebView
control doesn’t look so pretty, so we make some configuration changes, remove the padding around the control, and make some settings so the browser fits nicely in the screen area provided. If we’ve received a request for a specific fruit or vegetable to load, we look up the URL and load it; otherwise, we load the “default” Web page of Andy’s Veggie Garden about cherry tomatoes.
Now that you’ve implemented your Fragment
classes, you can place them in the appropriate layout resource files. You’ll need to create two layout files. In landscape mode, you’ll want a single activity_simple_fragments.xml
layout file to host both Fragment
components. In portrait mode, you’ll want a comparable layout file that hosts only the ListFragment
you implemented. The user interface of the WebViewFragment
you implemented will be generated at runtime.
Let’s start with the landscape-mode layout resource, called res/layout-land/activity_simple_fragments.xml
. Note that we store this activity_simple_fragments.xml
resource file in a special resource directory for landscape mode use only. We discuss how to store alternative resources in this way in depth in Chapter 13, “Designing Compatible Applications.” For now, suffice it to say that this layout will be automatically loaded whenever the device is in landscape mode.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar"
layout="@layout/tool_bar" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false">
<fragment
android:name="com.introtoandroid.simplefragments.VeggieGardenListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="200dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/veggieentry"
android:layout_weight="4"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
Here, we have a fairly straightforward LinearLayout
control wrapping another LinearLayout
that has two child controls. One is a static Fragment
component that references the custom ListFragment
class you implemented. For the second region, where we want to put the WebViewFragment
, we include a FrameLayout
region that we will replace with our specific VeggieGardenWebViewFragment
instance programmatically at runtime.
The resources stored in the normal layout directory will be used whenever the device is not in landscape mode (in other words, portrait mode). Here, we need to define two layout files. First, let’s define our static ListFragment
in its own res/layout/activity_simple_fragments.xml
file. It looks much like the previous version, without the second FrameLayout
control:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SimpleFragmentActivity">
<include
android:id="@+id/toolbar"
layout="@layout/tool_bar" />
<fragment
android:name="com.introtoandroid.simplefragments.VeggieGardenListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
tools:layout="@layout/activity_simple_fragments" />
</LinearLayout>
You’re almost done. Now you need to define your Activity
classes to host your Fragment
components. You’ll need two Activity
classes: a primary class as well as a secondary class that is used only to display the VeggieGardenWebViewFragment
when in portrait mode. Let’s call the primary Activity
class SimpleFragmentsActivity
and the secondary Activity
class VeggieGardenViewActivity
.
As mentioned earlier, moving all your user interface logic to Fragment
components greatly simplifies your Activity
class implementation. For example, here is the complete implementation for the SimpleFragmentsActivity
class:
public class SimpleFragmentsActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_fragments);
Toolbar toolbar;
Toolbar = (Toolbar) findViewById(R.id.toolbar);
getSupportActionBar(toolbar);
}
}
Yup. That’s all that is required. The VeggieGardenViewActivity
class is only slightly more interesting:
public class VeggieGardenViewActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE) {
finish();
return;
}
if (savedInstanceState == null) {
setContentView(R.layout.activity_simple_fragments);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
getSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
VeggieGardenWebViewFragment details = new VeggieGardenWebViewFragment();
details.setArguments(getIntent().getExtras());
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.list, details);
ft.commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
Here, we check that we’re in the appropriate orientation to be using this Activity
. Then we create an instance of the VeggieGardenWebViewFragment
and programmatically add it to the Activity
, generating its user interface at runtime by replacing the R.id.list
view, which is the root view of any Activity
class. That’s all that’s needed to implement this simple sample application with Fragment
components while including the Toolbar
component as an ActionBar
.
Fragments are so important to the future of the Android platform that the Android team provided a compatibility library so that developers can update their legacy applications as far back as Android 1.6, if they so choose. This library was originally called the Compatibility Package and is now called the Android Support Library package.
The choice of whether or not to update older applications is a personal one for the development team. Non-Fragment
applications should continue to function for the foreseeable future without error, mostly due to the Android team’s continued policy of supporting legacy applications as much as possible when new platform versions are released. Here are some considerations for developers with legacy applications who are considering whether or not to revise their existing code:
Leave your legacy application as is, and the ramifications are not catastrophic. Your application will not be using the latest and greatest features that the Android platform has to offer (and users will notice this), but it should continue to run as well as it always has without any additional work on your part. If you have no plans to update or upgrade your old applications, this may very well be a reasonable choice. The potentially inefficient use of screen space may be problematic but should not create new errors.
If your application has a lot of market traction and you’ve continued to update it as the Android platform has matured, you’re more likely to want to consider the Android Support Library package. Your users may demand it. You can certainly continue to support your legacy application and create a separate new-and-improved version that uses the new platform features, but this means organizing and managing different source code branches and different application packages, and it complicates application publication and reporting, not to mention maintenance and marketing complications. Better to revise your existing application to use the Android Support Library package and do your best to keep your single code base manageable. The size and resources of your organization may be contributing factors to the decision described here.
Just because you start using the Android Support Library package in your applications does not mean you have to implement every new feature (fragments, loaders, toolbars, and so on) immediately. You can simply pick and choose the features that make the most sense for your application and add others over time via application updates when your team has the resources and inclination.
Choosing not to update your code to new controls could leave your legacy application looking dated compared to other applications. If your application is already completely customized and isn’t using stock controls—often the case with games and other highly graphical apps—it may not need updating. If, however, you conform to stock system controls, look, and feel, it may be more important for your application to get a fresh look.
If you’re just starting to develop a new application and plan to target some of the older platform versions, incorporating fragments into your design is a much easier decision. If you’re just starting a project, there’s little reason not to use them and quite a few reasons why you should:
Regardless of what devices and platforms you are targeting now, there will be new ones in the future that you cannot foresee. Fragments give you the flexibility to easily adjust your user interface screen workflows without rewriting or retesting all your application code.
Incorporating the Android Support Library package into your applications early means that if other important platform features are added later, you’ll be able to update the libraries and start using them easily.
By using the Android Support Library package, your application will not show its age nearly as quickly since you will be incorporating the newer features of the platform and providing them to users on older platforms.
The Android Support Library package is simply a set of static support libraries (available as a .jar
file) that you can link to your Android application and use. You can download the Android Support Library package using the Android SDK Manager and then add it to the projects of your choice. It is an optional package and not linked by default. Android Support Library packages are versioned like everything else, and they are updated occasionally with new features—and more important, bug fixes.
Tip
You can find out more about the latest version package at the Android Developer website: http://d.android.com/tools/support-library/index.html.
There are actually seven Android Support Packages: v4, v7, v8, v13, v17, Annotation, and Design. The v4 package aims to provide new classes introduced in Honeycomb and beyond to platform versions as far back as API Level 4 (Android 1.6). This is the package you want to use when supporting your legacy applications. The v7 package provides additional APIs that are not found within the v4 package and is for supporting newer features all the way back to API Level 7 (Android 2.1); it is organized into the following groups: appcompat
, cardview
, gridlayout
, mediarouter
, palette
, and recyclerview
. The v8 package provides the renderscript
package to support RenderScript
computation all the way back to API Level 8 (Android 2.2). The v13 package provides more efficient implementations of some items, such as the FragmentCompat
, when running on API Level 13 and later. If you’re targeting API Level 13 or later, use this package instead. The v17 package provides widgets for building TV user interfaces, such as the BrowseFragment
, DetailsFragment
, PlaybackOverlayFragment
, and SearchFragment
. The Annotation
package allows you to add metadata annotations to your code, and the Design
package allows you to add material design patterns and user interface elements.
To use the Android Support Library package with your application, take the following steps:
1. Use the Android SDK Manager to download the Android Support Repository if you are developing with Android Studio. The Android Support Library item is for use with Eclipse.
2. Find your build.gradle
module file (not the build.gradle
project file) of your project listed in the Project
view of Android Studio and open the file.
3. In the dependencies section, add any support library features that your project needs to include by using their appropriate identifier and version number. For the SimpleFragments
application, we have added the support-v4
, appcompat-v7
, and the design
support library packages, each with a specified version of 23.0.0
, as shown here:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:support-v4:23.0.0"
compile "com.android.support:appcompat-v7:23.0.0"
compile 'com.android.support:design:23.0.0'
}
4. Begin using the additional support APIs available to your project. For example, to create a class extending FragmentActivity
, you need to import android.support.v4.app.FragmentActivity
.
Note
A few differences exist between the APIs used by the Android Support Library package and those found in the later versions of the Android SDK. However, there are some classes that are renamed to avoid name collisions, and not all classes and features are currently incorporated into the Android Support Library package.
Fragments are great for creating reusable interface components, but there are other ways to use fragments within your application. You can create reusable behavior components without a user interface, in addition to nesting fragments within fragments.
Fragments are not only for decoupling a user interface component from an Activity
. You may also want to decouple application behaviors, such as background processing, into a reusable Fragment
. Rather than providing the ID of a resource, you simply provide a unique string tag when adding or replacing a Fragment
. Because you are not adding a particular View
to your layout, the call to the onCreateView()
method is never called. Just make sure to use the findFragmentByTag()
to retrieve this behavior Fragment
from your Activity
.
Android 4.2 (API Level 17) introduced the ability to nest fragments within fragments. Nested fragments have also been added to the Android Support Library, making this API capability available all the way back to Android 1.6 (API Level 4). In order to add a Fragment
within another Fragment
, you must invoke the Fragment
method getChildFragmentManager()
, which returns a FragmentManager
. Once you have the FragmentManager
, you can start a FragmentTransaction
by calling beginTransaction()
and then invoking the add()
method, including the Fragment
to add and its layout, followed by the commit()
method. You can even use the getParentFragment()
method from within a child Fragment
to get the parent Fragment
for manipulation.
This opens many possibilities for creating dynamic and reusable nested components. Some examples include tabbed fragments within tabbed fragments, paging from one Fragment
item/Fragment
detail screen to the next Fragment
item/Fragment
detail screen with ViewPager
, paging fragments with ViewPager
within tabbed fragments, or nesting a behavior Fragment
without a UI inside a Fragment
with a UI, along with a host of many other nesting possibilities.
Fragments were introduced into the Android SDK to help address the different types of device screens that application developers need to target now and in the future. A Fragment
is simply a self-contained user interface or behavior, with its own lifecycle, that can be independent of a specific Activity
class. Fragments must be hosted within Activity
classes, but they give the developer a lot more flexibility when it comes to breaking screen workflow into components that can be mixed and matched in different ways, depending on the screen real estate available on the device. Fragments were introduced in Android 3.0, but legacy applications can use them if they take advantage of the Android Support Library package, which allows applications that target API Level 4 (Android 1.6) and higher to use these more recent additions to the Android SDK. In addition, the APIs with nested fragments provide even greater flexibility when creating reusable components for your applications.
1. What class facilitates coordination between an Activity
and its Fragment
components?
2. What method call is used for acquiring the class that facilitates coordination between an Activity
and its Fragment
components?
3. To what value should the android:name
attribute of the <fragment>
XML tag be set?
4. True or false: The onActivityAttach()
callback method is called when a Fragment
is first attached to a specific Activity
class.
5. What are some subclasses of the Fragment
(android.app.Fragment
) class?
6. What type of control does a ListFragment
(android.app.ListFragment
) host?
7. Fragments were introduced in API Level 11 (Android 3.0). How would you add Fragment
support to your application to support devices running versions of Android older than API Level 11?
1. Using the Android documentation, review how to add a Fragment
to the back stack. Create a simple application with a layout consisting of one Fragment
for inserting a number (start with 1 in the first Fragment
) and a button below it. Upon clicking the button, replace the first Fragment
with a second Fragment
and insert the number 2 in that Fragment
. Continue this capability all the way up to 10, and while doing so, add each Fragment
to the back stack to support back navigation.
2. Using Android Studio, create a new Phone and Tablet
Android project using the new project creation wizard, and on the Add an activity to Mobile
page, select the Master/Detail Flow
option, then select Finish
. Launch this application on both a handset and a tablet-size screen to see what it does, and then analyze the code to get a feel for how fragments have been used.
3. Create a two-pane Fragment
layout where both fragments are generated and inserted programmatically into a layout at runtime. Have each Fragment
take up 50% of the screen space, and use different colors for each Fragment
.
Android Training: “Building a Dynamic UI with Fragments”:
http://d.android.com/training/basics/fragments/index.html
Android API Guides: “Fragments”:
http://d.android.com/guide/components/fragments.html
Android SDK Reference regarding the application Fragment
class:
http://d.android.com/reference/android/app/Fragment.html
Android SDK Reference regarding the application ListFragment
class:
http://d.android.com/reference/android/app/ListFragment.html
Android SDK Reference regarding the application PreferenceFragment
class:
http://d.android.com/reference/android/preference/PreferenceFragment.html
Android SDK Reference regarding the application WebViewFragment
class:
http://d.android.com/reference/android/webkit/WebViewFragment.html
Android SDK Reference regarding the application DialogFragment
class:
http://d.android.com/reference/android/app/DialogFragment.html
Android Tools: “Support Library”:
http://d.android.com/tools/support-library/index.html
Android Developers Blog: “The Android 3.0 Fragments API”:
http://android-developers.blogspot.com/2011/02/android-30-fragments-api.html
18.118.120.206