time

In short about Android Fragments

Introduction

The primary advantage of Fragments is the ease with which you can create dynamic and flexible UI designs that can be adapted to suite a range of screen sizes — from small-screen smartphones to tablets. Each Fragment is an independent module that is tightly bound to the Activity into which it is placed. Fragments can be reused within multiple activities, as well as laid out in a variety of combinations to suit multipane tablet UIs and added to, removed from, and exchanged within a running Activity to help build dynamic UIs.

Following are important points about fragment:

  • A fragment has its own layout and its own behavior with its own lifecycle callbacks.
  • You can add or remove fragments in an activity while the activity is running.
  • You can combine multiple fragments in a single activity to build a multi-pane UI.
  • A fragment can be used in multiple activities.
  • Fragment life cycle is closely related to the lifecycle of its host activity which means when the activity is paused, all the fragments available in the acivity will also be stopped.
  • A fragment can implement a behavior that has no user interface component.
  • Fragments were added to the Android API in Honeycomb version of Android which API version 11.

You create fragments by extending Fragment class and you can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a <fragment/> element.

Following is a typical example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.

The application can embed two fragments in Activity A, when running on a tablet-sized device. However, on a handset-sized screen, there's not enough room for both fragments, so Activity A includes only the fragment for the list of articles, and when the user selects an article, it starts Activity B, which includes the second fragment to read the article.

Unlike Activities, Fragments don’t need to be registered in your manifest. This is because Fragments can exist only when embedded into an Activity, with their lifecycles dependent on that of the Activity to which they’ve been added.

Fragment Life Cycle

Android fragments have their own life cycle very similar to an android activity.

Phase I: When a fragment gets created, it goes through the following states:

  • onAttach()
  • onCreate()
  • onCreateView()
  • onActivityCreated()

Phase II: When the fragment becomes visible, it goes through these states:

  • onStart()
  • onResume()

Phase III: When the fragment goes into the background mode, it goes through these states:

  • onPaused()
  • onStop()

Phase IV: When the fragment is destroyed, it goes through the following states:

  • onPaused()
  • onStop()
  • onDestroyView()
  • onDestroy()
  • onDetach()
android_fragments_layout.png
Source: Professional Android TM 4 Application Development by Reto Meier.

Practical example

Each Activity includes a Fragment Manager to manage the Fragments it contains. You can access the Fragment Manager using the getFragmentManager method:

FragmentManager fragmentManager = getFragmentManager();

The Fragment Manager provides the methods used to access the Fragments currently added to the Activity, and to perform Fragment Transaction to add, remove, and replace Fragments.

The simplest way to add a Fragment to an Activity is by including it within the Activity’s layout using the fragment tag, as shown in following example.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment android:name="com.paad.weatherstation.PointsListFragment"
android:id="@+id/points_list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>

<fragment android:name="com.paad.weatherstation.PointDetailFragment"
android:id="@+id/point_detail_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3"
/>
</LinearLayout>

This technique works well when you use Fragments to define a set of static layouts based on various screen sizes. If you plan to dynamically modify your layouts by adding, removing, and replacing Fragments at run time, a better approach is to create layouts that use container Views into which Fragments can be placed at runtime, based on the current application state. Following example shows an XML snippet that you could use to support this latter approach.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/points_list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<FrameLayout
android:id="@+id/point_detail_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3"
/>
</LinearLayout>

You then need to create and add the corresponding Fragments to their appropriate parent containers within the onCreate handler of your Activity using Fragment Transactions.

Fragment Transactions can be used to add, remove, and replace Fragments within an Activity at run time. Using Fragment Transactions, you can make your layouts dynamic — that is, they will adapt and change based on user interactions and application state.

A new Fragment Transaction is created using the beginTransaction method from the Activity's Fragment Manager. Modify the layout using the add, remove, and replace methods. When you are ready to execute the change, call commit to add the transaction to the UI queue.

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

// add fragment
fragmentTransaction.add(R.id.points_list_fragment, new PointsListFragment());

// remove fragment
Fragment fragment = fragmentManager.findFragmentById(R.id.point_detail_fragment);
fragmentTransaction.remove(fragment);

// replace fragment
fragmentTransaction.replace(R.id.point_detail_fragment, new PointDetailFragment(selected_index));

fragmentTransaction.commit();

Following shows the skeleton code used to populate an Activity’s layout with Fragments at run time.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // inflate the layout containing the Fragment containers
    setContentView(R.layout.activity_main);

    FragmentManager fm = getFragmentManager();
    // check to see if the Fragment back stack has been populated
    // if not, create and populate the layout.
    PointDetailFragment detailFragment = (PointDetailFragment)fm.findFragmentById(R.id.point_detail_fragment);
    if (detailFragment == null) {
        FragmentTransaction ft = fm.beginTransaction();
        ft.add(R.id.point_detail_fragment, new PointDetailFragment());
        ft.add(R.id.points_list_fragment, new PointsListFragment());
        ft.commit();
    }
}
android_fragments_example.png

You can see code at github.

Useful links

comments powered by Disqus