9. Partitioning with Fragments

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.

Understanding 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.

Image

Figure 9.1 Traditional screen workflow without fragments.

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.

Image

Figure 9.2 Improved screen workflow with fragments.

Understanding the Fragment Lifecycle

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.

Defining Fragments

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" />

Managing Fragment Modifications

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:

Image A Fragment can be attached or reattached to the parent Activity.

Image 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.

Attaching and Detaching Fragments with Activities

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:

Image The onAttach() callback method is called when a Fragment is first attached to a specific Activity class.

Image The onCreate() callback method is called when a Fragment is first being created.

Image The onCreateView() callback method is called when the user interface layout, or View hierarchy, associated with the Fragment should be created.

Image The onActivityCreated() callback method will inform the Fragment when its parent Activity class’s onCreate() method has completed.

Image The onStart() callback method is called when the Fragment’s user interface becomes visible but is not yet active.

Image 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.

Image 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.

Image 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.

Image The onDestroyView() callback method is called to clean up any user interface layout, or View hierarchy resources, associated with the Fragment.

Image The onDestroy() callback method is called to clean up any other resources associated with the Fragment.

Image The onDetach() callback method is called just before the Fragment is detached from the Activity class.

Working with Special Types of Fragments

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:

Image ListFragment (android.app.ListFragment): Much like a ListActivity, this Fragment class hosts a ListView control.

Image PreferenceFragment (android.preference.PreferenceFragment): Much like a PreferenceActivity, this Fragment class lets you easily manage user preferences.

Image 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.

Image 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.”


Image 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.


Designing Fragment-Based Applications

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.


Image 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).

Image

Figure 9.3 One fragment per Activity/screen.

In landscape mode, we will display both fragments on the same screen within the same AppCompatActivity class, as shown in Figure 9.4.

Image

Figure 9.4 Both fragments in a single Activity/screen.

Implementing a ListFragment

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.

Implementing a WebViewFragment

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.

Defining the Layout Files

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>

Defining the Activity Classes

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.

Using the Android Support Library Package

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.

Adding Fragment Support to Legacy Applications

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:

Image 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.

Image 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.

Image 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.

Image 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.

Using Fragments in New Applications Targeting Older Platforms

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:

Image 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.

Image 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.

Image 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.

Linking the Android Support Package to Your Project

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.


Image 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.


Image 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.


Additional Ways to Use Fragments

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.

Behavior Fragments without a User Interface

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.

Exploring Nested Fragments

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.

Summary

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.

Quiz Questions

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?

Exercises

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.

References and More Information

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

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.120.206