Now that we understand the lifecycle of fragments, we can look at some of the specialized versions of the Fragment class. As we go through each of these specialized classes, remember they all ultimately inherit from the Fragment class and therefore experience the same lifecycle behavior. Many of these specialized classes have an impact on what operations are safe to perform at the various points in the lifecycle, and some of these classes even add their own lifecycle methods. Understanding each of these classes and their interaction with the fragment lifecycle is essential for using the classes effectively.
One of the simplest fragment-derived classes to use and yet one of the most helpful is the ListFragment class. The ListFragment class provides a fragment that encapsulates a ListView and, as the name implies, is useful for displaying lists of data.
Unlike the base Fragment class, we're not required to override the onCreateView callback method for the ListFragment class. The ListFragment class provides a standard appearance and only requires that we associate some data. The ListFragment class does all the work of creating the view hierarchy and displaying that data.
We associate data with the ListFragment class by calling the ListFragment class' setListAdapter method and passing a reference to an object that implements the ListAdapter interface. Android provides a number of classes that implement this interface such as ArrayAdapter, SimpleAdapter, and SimpleCursorAdapter. The specific class you use will depend on how your source data is stored. If none of the standard Android classes meet your specific requirements, you can create a custom implementation reasonably easy.
For a discussion about creating a custom list adapter, see the Android tutorial Displaying the Quick Contact Badge at http://developer.android.com/training/contacts-provider/display-contact-badge.html.
The call to setListAdapter requires that the view hierarchy for the ListFragment be completely constructed. As a result, we normally do not call the setListAdapter method any earlier than the onActivityCreated callback method.
The ListFragment class wraps an instance of the ListView class, which is accessible through the getListView method. In most scenarios, we can feel free to interact with the contained ListView instance directly and take advantage of any features offered by the ListView class. The one very important exception is when we set the ListAdapter instance. Both the ListFragment and ListView classes expose a setListAdapter method, but we must be sure to use the ListFragment version of the method.
The ListFragment class relies on certain initialization behaviors that occur within the ListFragment.setListAdapter method; therefore, the process of calling the setListAdapter method directly on the contained ListView instance bypasses this initialization behavior and may cause the application to become unstable.
Up until now, our application has used a fixed layout of several RadioButton views to display the list of books. Using a fixed layout to display such options is not generally a good choice, because any changes to the book list require that we go in and directly modify the fragment layout. In practice, we would prefer to have a layout that is independent of the specific titles. We could write code to dynamically generate the RadioButton views, but there is an easier way. We can instead use the ListFragment class.
By switching our application to use the ListFragment class, we can simply store the list of book titles in an array resource and associate the contents of that array resource with the ListFragment instance. In the event of adding more titles or needing to change one of the titles, we simply modify the array resource file. There is no need for us to make any changes to the actual fragment layout.
Our application already has all the book titles stored as individual string resources, so we just need to add an array resource for them. We'll add the book titles array to the arrays.xml resource file within the values resource folder where we currently have an array resource defined to hold the list of book descriptions.
Within the resources root element of the arrays.xml resource file, add a string-array element that includes a name attribute with a value of bookTitles. Within the string-array element, add an item for each book title that references the string resource for each title. We want to be sure that we list the book title array entries in the same order as the bookDescription array entries because we use the array index as the ID value for each book when we notify the activity of the user's book selection. The array resource entries for the book title and description arrays appear as follows:
<resources>
<!-- Book Titles -->
<string-array name="bookTitles">
<item>@string/dynamicUiTitle</item>
<item>@string/android4NewTitle</item>
<item>@string/androidSysDevTitle</item>
<item>@string/androidEngineTitle</item>
<item>@string/androidDbProgTitle</item>
</string-array>
<!-- Book Descriptions -->
<string-array name="bookDescriptions">
<item>@string/dynamicUiDescription</item>
<item>@string/android4NewDescription</item>
<item>@string/androidSysDevDescription</item>
<item>@string/androidEngineDescription</item>
<item>@string/androidDbProgDescription</item>
</string-array>
</resources>With the titles stored as an array resource, we can now easily create a ListFragment derived class to display the book titles.
The first step is to add a new class to our project. To do this, we'll create a new class named BookListFragment2 that extends the ListFragment class as shown in the following code line:
class BookListFragment2 extends ListFragment { }Next, we override the onActivityCreated method as follows:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] bookTitles =
getResources().getStringArray(R.array.bookTitles);
ArrayAdapter<String> bookTitlesAdapter =
new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, bookTitles);
setListAdapter(bookTitlesAdapter);
}In the onActivityCreated method, we first call the base class implementation that is required by all classes that extend ListFragment. We then load the bookTitles array resource and associate it with an instance of the ArrayAdapter class named bookTitlesAdapter. The array adapter takes the context as the first parameter, which we get by accessing the activity, and takes the array as the third parameter. The second parameter is the ID of the resource to use to lay out each entry in the list. This resource can be a custom resource or one of the built-in Android resources. In our case, we're using the built-in Android layout resource android.R.layout.simple_list_item_1, which displays a single string value for each row within the ListView. The last step is to call the setListAdapter method and pass the bookTitlesAdapter method.
Creating a custom layout resource for the ListFragment class is just like doing so for the ListView class, and is discussed in detail in the Android developer documentation: http://developer.android.com/reference/android/app/ListFragment.html.
For our application to work correctly, we need to inform the activity each time the user selects one of the titles. Because we use an interface to loosely couple our fragment with the activity, this turns out to be a pretty simple task.
We first override the ListFragment class' onListItemClick method. The ListFragment class calls the onListItemClick method when the user selects an entry within the ListFragment instance. The onListItemClick method receives several selection-related parameters including the zero-based position of the selection. Our ListFragment is loaded from an array, so this position value corresponds to the selected title's array index.
With the position parameter value corresponding directly to the array index, all we have to do to inform the activity of the user selection is get a reference to the activity, cast it to our OnSelectionChangeListener interface, and call the interface's onSelectedBookChanged method, passing the position parameter value as shown in this code:
public void onListItemClick(ListView l, View v, int position, long id) {
// Access the Activity and cast to the inteface
OnSelectedBookChangeListener listener =(OnSelectedBookChangeListener)
getActivity();
// Notify the Activity of the selection
listener.onSelectedBookChanged(position);
}All the activity classes in our application that will use our BookListFragment2 class already implement the OnSelectionChangeListener interface, so there is no change required to the activity classes.
We now update the activity_main.xml resource file to use the BookListFragment2 class instead of the original BookListFragment class as shown in the following code:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- List of Book Titles ** using the ListFragment **-->
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="com.jwhh.fragments.BookListFragment2"
android:id="@+id/fragmentTitles"/>
<!-- Description of selected book -->
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="com.jwhh.fragments.BookDescFragment"
android:id="@+id/fragmentDescription"/>
</LinearLayout>We need to make the same change in the activity_main_wide.xml file.
Our program is now fully functional using the ListFragment class and appears as follows:

Any changes that we need to make to the titles can now all be made in the resources file and require no changes to the user interface code.
Up until now we've been looking at fragments as a new way to divide our application's user interface into subsections of the available display area. Although fragments are new, the concept of having an aspect of our application user interface as a subsection of the available display area is not new. Any time an application displays a dialog, the application is doing exactly that.
Historically, the challenge of working with dialogs is that even though they are conceptually just another window within an application, we must handle many of the tasks related to dialogs differently than other aspects of our application user interface. Doing something as simple as handling a button click requires a dialog-specific interface, DialogInterface.OnClickListener, rather than the View.OnClickListener interface that we use when handling a click event from non-dialog related parts of our user interface code. An even more complicated issue is that of orientation changes. Dialogs automatically close in response to an orientation change and therefore can create inconsistent application behavior if a user changes device orientation while a dialog is visible.
The DialogFragment class eliminates much of the special handling related to dialogs. With the DialogFragment class, displaying and managing a dialog becomes much more consistent with other aspects of our application user interface.
When an application displays an instance of the DialogFragment class, the window for the DialogFragment instance has up to three parts to it: layout area, title, and frame. A DialogFragment instance always contains the layout area, but we can control whether it includes the title and frame by setting the DialogFragment class' style using the setStyle method. The DialogFragment class supports four styles with an instance of the DialogFragment class having exactly one style applied. The following table shows the four available styles:
|
Style |
Has Title |
Has Frame |
Accepts Input |
|---|---|---|---|
|
|
Yes |
Yes |
Yes |
|
|
No |
Yes |
Yes |
|
|
No |
No |
Yes |
|
|
No |
No |
No |
Notice that the styles remove features cumulatively. For example, STYLE_NO_TITLE indicates no title whereas STYLE_NO_FRAME indicates no frame and no title. If we do not call the setStyle method, Android creates the DialogFragment instance with the style set to STYLE_NORMAL.
The style affects the remainder of the behavior of the DialogFragment class and therefore must be set in the onCreate callback method. An attempt to set the DialogFragment class' style any later in the lifecycle is ignored.
If you wish to provide the dialog with a special theme, the theme's resource ID can also be passed to the setStyle method. To allow Android to select an appropriate theme based on the style, simply pass 0 as the theme resource ID. The following code sets the DialogFragment instance to have no title and use the Android-selected theme for that style:
class MyDialogFragment extends DialogFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, 0);
}
}Populating the layout of an instance of the DialogFragment class is just like that of a standard fragment derived class. We simply override the onCreateView method and inflate the layout resource.
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View theView = inflater.inflate(R.layout.fragment_my_dialog,
container, false);
return theView;
}Creating a layout resource for use with a DialogFragment derived class works exactly as creating a layout resource for any other fragment derived class. To have our DialogFragment instance display a line of text and two buttons, we define the fragment_my_dialog.xml layout resource as shown in the following XML:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Text -->
<TextView
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1"
android:text="@string/dialogSimpleFragmentPrompt"
android:layout_margin="16dp"/>
<!-- Two buttons side-by-side -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0px"
android:orientation="horizontal"
android:layout_weight="3">
<Button
android:id="@+id/btnYes"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/text_yes"
android:layout_margin="16dp"/>
<Button
android:id="@+id/btnNo"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/text_no"
android:layout_margin="16dp"/>
</LinearLayout>
</LinearLayout>Displaying our DialogFragment derived class is largely just a matter of creating the class instance and calling the show method. We need to keep in mind though that although our DialogFragment instance appears as a standard dialog when it displays, it is actually a fragment. Like all fragments, it is managed by the containing activity's FragmentManager instance. As a result, we need to pass a reference to the activity's FragmentManager instance as part of the call to the DialogFragment class show method as we do in the following code:
MyDialogFragment theDialog = new MyDialogFragment(); theDialog.show(getFragmentManager(), null);
With our DialogFragment derived class' style set to STYLE_NO_TITLE and using the fragment_my_dialog.xml layout resource file shown earlier, the previous code displays the following:

One of the key values of the DialogFragment class is that it provides greater consistency in our code than is available when using the traditional Dialog class. Most aspects of working with the DialogFragment class are the same as when working with other fragments. No longer does displaying a dialog have to be handled so much differently than other aspects of our application user interface. For example, no special handling is required to deal with orientation changes. Another place where this greater consistency is evident is in event handling, because our button click event handling can use the standard view class event interfaces.
To handle the button clicks, our DialogFragment derived class simply implements the View.OnClickListener interface. The following code shows setting the yes and no button click events to call back to our DialogFragment derived class in our class' onCreateView callback method:
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View theView = inflater.inflate(
R.layout.fragment_my_dialog, container, false);
// Connect the Yes button click event and request focus
View yesButton = theView.findViewById(R.id.btnYes);
yesButton.setOnClickListener(this);
yesButton.requestFocus();
// Connect the No button click event
View noButton = theView.findViewById(R.id.btnNo);
noButton.setOnClickListener(this);
return theView;
}Notice that we're setting up the button click handling just as we would if we were working within any other fragment or even directly within the activity.
We can also handle notifying the activity of the user's interaction with the DialogFragment derived class consistently with the way we do with other fragments. Just as we did in the previous chapter, our DialogFragment derived class simply provides an interface for notifying the activity which of the available buttons the user selects, as shown in the following code:
public class MyDialogFragment extends DialogFragment
implements View.OnClickListener {
// Interface Activity implements for notification
public interface OnButtonClickListener {
void onButtonClick(int buttonId);
}
// Other members elided for clarity
}As long as the activity implements the interface, our DialogFragment derived class can notify the activity of which button the user clicked.
In the handler for our button click events, we'll follow the same pattern we did in the previous chapter. We access the containing activity, cast it to the expected interface, and call the interface method, as shown in the following code:
public void onClick(View view) {
int buttonId = view.getId();
// Notify the Activity of the button selection
OnButtonClickListener parentActivity =
(OnButtonClickListener) getActivity();
parentActivity.onButtonClick(buttonId);
// Close the dialog fragment
dismiss();
}Notice that there is one bit of special handling in the previous method. Just as with the traditional Dialog class, we must call the dismiss method on the DialogFragment derived class when we no longer wish to display it.
Although we treat our DialogFragment derived class as just another fragment, it still has a part of its identity that is tied to the traditional Dialog class. In fact, Android actually wraps our DialogFragment derived class within a traditional Dialog instance. This occurs in a callback method, specific to the DialogFragment class, named onCreateDialog that Android calls just prior to calling the onCreateView callback method.
The Dialog instance that the onCreateDialog method returns is the window that is ultimately displayed to the user. The layout we create within our DialogFragment derived class is simply wrapped within the Dialog window. We can access that Dialog instance later in the lifecycle to access Dialog related behavior or even override the method to provide our own Dialog instance.
Accessing the Dialog related behavior of our DialogFragment derived class requires a reference to the Dialog instance created in the onCreateDialog method. We retrieve that reference by calling the getDialog method. Once we have the reference to the Dialog instance, we can access aspects of the class' dialog identity that are not otherwise available.
When we create a DialogFragment derived class with the style set to STYLE_NORMAL, the displayed dialog includes a title area above the layout area. The value of the title can only be set by calling the setTitle method on the Dialog instance that wraps our DialogFragment instance. A similar issue comes up in dealing with the dialog cancellation behavior. By default, the user can cancel a dialog by tapping on the activity behind the dialog. In many cases, this may be unacceptable as we want to require the user to acknowledge one of the choices within the dialog. The following code sets these Dialog related behaviors after the button click handling is set up:
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View theView = inflater.inflate(R.layout.fragment_my_dialog, container, false);
View yesButton = theView.findViewById(R.id.btnYes);
yesButton.setOnClickListener(this);
yesButton.requestFocus();
View noButton = theView.findViewById(R.id.btnNo);
noButton.setOnClickListener(this);
// Set the dialog aspects of the dialog fragment
Dialog dialog = getDialog();
dialog.setTitle(getString(R.string.myDialogFragmentTitle));
dialog.setCanceledOnTouchOutside(false);
return theView;
}The code first sets the dialog title and then sets the option to prevent the user from closing the dialog by tapping on the activity window. For the call to the setTitle method to work, we will need to change the call to the setStyle method in the onCreate callback method to set the style to STYLE_NORMAL so that the dialog will have a title area.
There may be times where we like the programming consistency that the DialogFragment class offers, but want to take advantage of the features provided by a class that derives from the traditional Dialog class. By overriding the DialogFragment class' onCreateDialog method, we can do exactly that. Overriding the onCreateDialog method allows us to replace the DialogFragment class' default Dialog instance with one we create. A great example of when this is useful is in leveraging the Android AlertDialog class.
The AlertDialog class provides a variety of default behaviors and allows us to display text, an icon, and buttons all without having to create a layout resource. There is something we must keep in mind when we're leveraging a class that inherits from the traditional Dialog class. Although outside interaction with our class will be consistent with other DialogFragment derived classes, any interactions with the traditional Dialog class that occur within our DialogFragment derived class will be done in the traditional Dialog class way. For example, to create a DialogFragment derived class that utilizes the AlertDialog class requires that our class implements the Dialog class way of handling click events that is to implement the DialogInterface.OnClickListener interface as shown in the following code:
public class AlertDialogFragment extends DialogFragment
implements DialogInterface.OnClickListener{ }Within our class' onCreateDialog method, we create the AlertDialog instance using the AlertDialog.Builder class just as if we were going to display the AlertDialog instance directly. Within the onCreateDialog method we set all the options on the AlertDialog.Builder instance, including the title, message, icon, and buttons. Notice, though, that we never call the AlertDialog.Builder class' show method, but instead call its create method. We then take the reference to the newly created AlertDialog instance and return it from the onCreateDialog method. All of these steps are shown in the following code:
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Create the Builder for the AlertDialog
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
// Set the AlertDialog options
builder.setTitle(R.string.alert_dialog_title)
.setMessage(R.string.alert_dialog_message)
.setIcon(R.drawable.ic_launcher)
.setCancelable(false)
.setPositiveButton(R.string.text_yes, this)
.setNegativeButton(R.string.text_no, this);
// Create and return the AlertDialog
AlertDialog alertDialog = builder.create();
return alertDialog;
}The Dialog instance we create is now managed as a part of the DialogFragment instance. Everything else we do with our AlertDialogFragment class will be just as it is with the other DialogFragment derived classes we create.
When our app shows our AlertDialogFragment class, it appears as the following screenshot:

Notice that we didn't need to override the onCreateView callback method, because the Dialog instance we create in the onCreateDialog callback method provides the desired display characteristics.
Overriding the DialogFragment class' onCreateDialog callback method is a powerful technique that allows us to enjoy the benefits of the DialogFragment class while still leveraging existing investment we may have in traditional Dialog classes, whether they be a built-in class such as the AlertDialog class or some custom Dialog class we may have as part of our own code library.