Tech and Media Labs
This site uses cookies to improve the user experience.




Android Fragment

Jakob Jenkov
Last update: 2014-11-05

An Android fragment is a GUI component which can "live" inside an Activity. An Android fragment is not by itself a subclass of View which most other GUI components are. Instead, a fragment has a view inside it. It is this view which is eventually displayed inside the activity in which the fragment lives.

Because an Android fragment is not a view, adding it to an activity looks somewhat different than adding a view (e.g. TextView). A fragment is added to a ViewGroup inside the activity. The fragment's view is displayed inside this ViewGroup. The following diagram shows what happens when you add a fragment to an activity:

Overview of how an Android fragment is added to an activity.

First the activity obtains a reference to the fragment. Then it gets a reference to the ViewGroup the fragment's view will be rendered inside. Then the activity adds the fragment. The fragment then creates its view and returns it to the activity. The view is then inserted into the ViewGroup parent, and the fragment is alive.

Create a Fragment

To create a fragment you must do two things:

  • Create a Fragment class.
  • Create a Fragment layout XML file.

Create a Fragment Class

To create a Fragment class, create an ordinary Java class which extends android.app.Fragment. Here is an example:

import android.app.Fragment;


public class MyFragment extends Fragment {

}

onCreateView()

This Fragment subclass isn't doing anything yet. The MyFragment class needs to override the method onCreateView() inherited from Fragment in order to create the fragment's View which is to be displayed inside the activity the fragment is added to. Here is an example fragment onCreateView() implementation:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parentViewGroup,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_my, parentViewGroup, false);
        return rootView;
    }
}

The onCreateView() method gets a LayoutInflater, a ViewGroup and a Bundle as parameters.

The LayoutInflater is an component which can create View instance based on layout XML files. As you can see, the example actually does that by calling layout.inflate() .

The inflate() method takes three parameters: The id of a layout XML file (inside R.layout), a parent ViewGroup into which the fragment's View is to be inserted, and a third boolean telling whether the fragment's View as inflated from the layout XML file should be inserted into the parent ViewGroup. In this case we pass false because the View will be attached to the parent ViewGroup elsewhere, by some of the Android code we call (in other words, behind our backs). When you pass false as last parameter to inflate(), the parent ViewGroup is still used for layout calculations of the inflated View, so you cannot pass null as parent ViewGroup .

The ViewGroup parameter of onCreateView() is the parent ViewGroup into which the View of the fragment is to be inserted. This is a ViewGroup inside the activity that will "host" the fragment.

The Bundle parameter of onCreateView() is a Bundle into which the fragment can save information, just like an Activity can.

Add a Fragment to an Activity

In order to have a fragment's View displayed inside an activity, you must add the fragment to the activity. You do so inside the activity. Here is an example which adds a fragment from inside onCreate() of the activity:

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        if (savedInstanceState == null) {
            getFragmentManager()
                    .beginTransaction()
                    .add(R.id.fragmentParentViewGroup, new MyFragment())
                    .commit();
        }
    }

}

The fragment is added inside the if statement. Unlike other View components, the activity remembers what fragments were added to the activity. Therefore you should only add a fragment to an activity once in the activity's life span, or the fragment will appear multiple times. This is true even if the user changes orientation of the device between portrait and landscape, and even if the activity will be destroyed in this process. The Android OS will remember that a fragment was added to this activity when a new activity of this kind is created, and will re-attach the fragment to the activity.

If the savedInstanceState is null then this is the first time any state is created for this activity, so no fragment has been added to it yet. Remember, if an app is completely destroyed by Android, so is its savedInstanceState Bundle variable, and then you need to re-attach the fragment when the activity is started.

Fragments must be added (or replaced or removed) inside a FragmentTransaction. You obtain a FragmentTransaction via the FragmentManager. You get the FragmentManager via the getFragmentManager() method. From the FragmentManager you can obtain a FragmentTransaction by calling the beginTransaction() method. On the FragmentTransaction returned by beginTransaction() you can now add, replace or remove fragments to the activity.

It is the add() method on the FragmentTransaction which adds the fragment to the activity. The add() method takes two parameters. The first parameter is the id of the parent ViewGroup into which the fragment's View is to be inserted. The second parameter is an instance of the fragment to add.

When you are done adding, replacing or removing fragments you must commit the FragmentTransaction . You do so by calling the commit() method on the FragmentTransaction. Only when the FragmentTransaction is committed will all the changes you have made take effect.

Here is the activity's layout XML file. Notice the id of the root element is the same as referenced in the R.layout constant collection.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:id="@+id/fragmentParentViewGroup"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context=".MyActivity"
             tools:ignore="MergeRootFrame" />

This layout XML file has only a single FrameLayout element. This FrameLayout element is used as the parent ViewGroup for the fragment. Thus, in practice the fragment will take up the whole screen. You could have used a different ViewGroup as parent for the fragment. Here is an activity layout XML file example that shows how that could look:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".MyActivity"

        >

    <TextView
            android:text="Activity Title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />

    <LinearLayout
            android:id="@+id/fragmentParentViewGroup"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">


    </LinearLayout>

</LinearLayout>    

Notice how the inner LinearLayout element has the id fragmentParentViewGroup . The fragment will use this LinearLayout as parent ViewGroup .

The Fragment Life Cycle

An Android fragment has a life cycle which is similar to the activity life cycle. The fragment life cycle is illustrated here:

The Android fragment life cycle.

First a fragment is added to an activity. This kicks off the fragment life cycle.

Second, the methods onAttach(), onCreate(), onCreateView(), onActivityCreated(), onStart() and onResume() are called. The onActivityCreated() is called when the hosting activity is fully created.

If the fragment is removed from its hosting activity, or the activity hosting the fragment is moved to the background of the app (another activity is moved to the foreground), then the onPause(), onStop() and onDestroyView() methods are called. If the fragment is returned to visibility, the fragment may transition from onDestroyView() to onCreateView() and become visible again.

Replace a Fragment

You can replace a fragment added to an activity with another fragment. You do so via the replace() method on the FragmentTransaction object. Here is a FragmentTransaction replace() example:

getFragmentManager().beginTransaction()
    .replace(R.id.fragmentParentViewGroup, new MySecondFragment())
    .commit();

You can replace fragments while the activity is still alive. Once the activity is destroyed you can no longer replace fragments inside it.

You can replace fragments as many times as you want. You can replace fragments as a way to change part of the user interface, or the whole user interface if that is what you need / prefer.

Remove a Fragment

You can remove a fragment from an activity using the FragmentTransaction. You do so via the remove() method. Here is a FragmentTransaction remove() example:

getFragmentManager().beginTransaction()
        .remove(mySecondFragment)
        .commit();

The remove() method takes a single parameter: A reference to the fragment to remove. The fragment will be removed from any parent ViewGroup the fragment was added to.

Adding Fragment Transactions to the Back Stack

You can add a fragment transaction to the back stack. The back stack keeps track of actions in your app which can be backtracked when the user clicks Android's standard "back" button on the device. If you add a fragment transaction to the back stack then the transaction can be backtracked (reversed) with a click on the back button on the device.

Here is an example showing how to add a fragment transaction to the back stack:

MySecondFragment mySecondFragment = new MySecondFragment();

getFragmentManager().beginTransaction()
        .replace(R.id.fragmentParentViewGroup, mySecondFragment)
        .addToBackStack(null)
        .commit();

This example replaces whatever fragment that was already added to the parent view group with the id R.id.fragmentParentViewGroup with the MySecondFragment instance. The example also adds the replacement transaction to the back stack. The addToBackStack() method takes an optional String parameter which can identify this state on the back stack. Most of the time you won't need this parameter so passing null is sufficient.

When this replacement transaction has been committed, it can be reversed by the user clicking the Android device's back button, in the same way the back button can take the user back to the previously visible activity.

Jakob Jenkov




Copyright  Jenkov Aps
Close TOC