Support free tutorials:











vogella training Training Books



Multi-pane development in Android with Fragments - Tutorial

Lars Vogel

Version 11.4

29.04.2014

Revision History
Revision 0.1 - 11.4 04.07.2009 - 29.04.2014   created, bug fixing and enhancements

Using Fragments in Android applications

This tutorial describes how to use the Fragment class in Android applications to create multi-pane layouts, i.e., applications which scale to the available width of the device. It is based on Eclipse 4.3 (Kepler), Java 1.6 and Android 4.4.


Table of Contents

1. Android Basics
2. Fragments
2.1. What are fragments?
2.2. Advantages of using fragments
2.3. How to work with Fragments
3. Fragment life-cycle
4. Defining and using Fragments
4.1. Defining fragments
4.2. Adding fragments statically
4.3. Fragment life cycle
4.4. Application communication with fragments
5. Persisting data in fragments
5.1. Persisting data between application restarts
5.2. Persisting data between configurations changes
6. Modifying Fragments at runtime
7. Animations for Fragment transition
8. Adding Fragments transition to the backstack
9. Fragments for background processing
9.1. Headless Fragments
9.2. Retained headless fragments to handle configuration changes
10. Fragments Tutorial
10.1. Overview
10.2. Create standard layouts
10.3. Create Fragment classes
10.4. RssfeedActivity
10.5. Run
11. Fragments Tutorial - layout for portrait mode
11.1. Create layouts for portrait mode
11.2. DetailActivity
11.3. Adjust the RssfeedActivity activity
11.4. Run
12. Dynamics Fragments Exercise
12.1. Target
12.2. Use placeholder for the fragments
12.3. Use fragment manager to replace fragments
13. Support this website
13.1. Thank you
13.2. Questions and Discussion
14. Links and Literature
14.1. Source Code
14.2. Android Resources
14.3. vogella Resources

1. Android Basics

The following description assumes that you have already basic knowledge in Android development.

Please check the Android development tutorial to learn the basics. Also see Android development tutorials for more information about Android development.

2. Fragments

2.1. What are fragments?

A fragment is an independent component which can be used by an activity. A fragment encapsulates functionality so that it is easier to reuse within activities and layouts.

A fragment runs in the context of an activity, but has its own life cycle and typically its own user interface. It is also possible to define fragments without an user interface, i.e., headless fragments.

Fragments can be dynamically or statically added to an activity.

2.2. Advantages of using fragments

Fragments make it easy to reuse components in different layouts, e.g., you can build single-pane layouts for handsets (phones) and multi-pane layouts for tablets. This is not limited to tablets; for example, you can use fragments also to support different layout for landscape and portrait orientation on a smartphone.

The typical example is a list of items in an activity. On a tablet you see the details immediately on the same screen on the right hand side if you click on item. On a smartphone you jump to a new detail screen. This is depicted in the following graphic.

Fragments usage on a handheld device

The following discussion will assume that you have two fragments (main and detail), but you can also have more. We will also have one main activity and one detailed activity. On a tablet the main activity contains both fragments in its layout, on a handheld it only contains the main fragment.

The following screenshots demonstrates this usage.

Fragments usage on a tablet device

2.3. How to work with Fragments

To create different layouts with fragments you can:

  • Use one activity, which displays two fragments for tablets and on handset devices. In this case you would switch the fragments in the activity whenever necessary. This requires that the fragment is not declared in the layout file as such fragments cannot be removed during runtime.

  • Use separate activities to host each fragment on a handset. For example, when the tablet UI uses two fragments in an activity, use the same activity for handsets, but supply an alternative layout that includes just one fragment. When you need to switch fragments, start another activity that hosts the other fragment.

The second approach is the most flexible and in general preferable way of using fragments. In this case the main activity checks if the detail fragment is available in the layout. If the detailed fragment is there, the main activity tells the fragment that it should update itself. If the detail fragment is not available, the main activity starts the detailed activity.

3. Fragment life-cycle

The life-cycle of a fragment is connected to the life-cycle of its hosting activity.

Fragments lifecycle

Table 1. Fragment life-cycle

Method Description
onAttach() The fragment instance is associated with an activity instance.The activity is not yet fully initialized
onCreate() Fragment is created
onCreateView() The fragment instance creates its view hierarchy. The inflated views become part of the view hierarchy of its containing activity.
onActivityCreated() Activity and fragment instance have been created as well as thier view hierarchy. At this point, view can be accessed with the findViewById() method. example.
onResume() Fragment becomes visible and active.
onPause() Fragment is visibile but becomes not active anymore, e.g., if another activity is animating on top of the activity which contains the fragment.
onStop() Fragment becomes not visible.

4. Defining and using Fragments

4.1. Defining fragments

To define a new fragment you either extend the android.app.Fragment class or one of its subclasses, for example, ListFragment, DialogFragment, PreferenceFragment or WebViewFragment. The following code shows an example implementation.

package com.example.android.rssfeed;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class DetailFragment extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rssitem_detail,
        container, false);
    return view;
  }

  public void setText(String item) {
    TextView view = (TextView) getView().findViewById(R.id.detailsText);
    view.setText(item);
  }
} 

4.2. Adding fragments statically

To use your new fragment, you can statically add it to an XML layout.

To check if the fragment is already part of your layout you can use the FragmentManager class.

DetailFragment fragment = (DetailFragment) getFragmentManager().
  findFragmentById(R.id.detail_frag);
if (fragment==null || ! fragment.isInLayout()) {
  // start new Activity
  }
else {
  fragment.update(...);
} 

If a fragment is defined in an XML layout file, the android:name attribute points to the corresponding class.

4.3. Fragment life cycle

A fragment has its own life cycle. But it is always connected to the life cycle of the activity which uses the fragment.

The onCreate() method is called after the onCreate() method of the activity but before the onCreateView() method of the fragment.

The onCreateView() method is called by Android once the fragment should create its user interface. Here you can inflate a layout via the inflate() method call of the Inflator object passed as a parameter to this method. There is no need to implement this method for headless fragments.

The onActivityCreated() is called after the onCreateView() method when the host activity is created. Here you can instantiate objects which require a Context object.

Fragments don't subclass the Context you have to use the getActivity() method to get the parent activity.

The onStart() method is called once the fragment gets visible.

If an activity stops, its fragments are also stopped; if an activity is destroyed, its fragments are also destroyed.

4.4. Application communication with fragments

To increase reuse of fragments, they should not directly communicate with each other. Every communication of the fragments should be done via the host activity.

For this purpose a fragment should define an interface as an inner type and require that the activity, which uses it, must implement this interface. This way you avoid that the fragment has any knowledge about the activity which uses it. In its onAttach() method it can check if the activity correctly implements this interface.

For example, assume you have a fragment which should communicate a value to its parent activity. This can be implemented like the following.

package com.example.android.rssfeed;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public class MyListFragment extends Fragment {

  private OnItemSelectedListener listener;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rsslist_overview,
        container, false);
    Button button = (Button) view.findViewById(R.id.button1);
    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        updateDetail();
      }
    });
    return view;
  }

  public interface OnItemSelectedListener {
    public void onRssItemSelected(String link);
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (activity instanceof OnItemSelectedListener) {
      listener = (OnItemSelectedListener) activity;
    } else {
      throw new ClassCastException(activity.toString()
          + " must implemenet MyListFragment.OnItemSelectedListener");
    }
  }

  @Override
  public void onDetach() {
    super.onDetach();
    listener = null;
  }

  // may also be triggered from the Activity
  public void updateDetail() {
    // create a string just for testing
    String newTime = String.valueOf(System.currentTimeMillis());

    // inform the Activity about the change based
    // interface defintion
    listener.onRssItemSelected(newTime);
  }
} 

5. Persisting data in fragments

5.1. Persisting data between application restarts

In fragments you also need to store your application data. For this you can persist the data in a central place. For example,

  • SQlite database

  • File

  • The application object if this case the application need to handle the storage

5.2. Persisting data between configurations changes

If you want to persist data between configuration changes, you can also use the application object.

In addition to that you can use the setRetainState(true) method call on the fragments . This retains fragment instances between configuration changes but only works if the fragments are not added to the backstack. Using this method is not recommend by Google for fragments which have an user interface. In this case the data must be stored as member (field).

If the data, which should be stored, is supported by the Bundle class, you can use the onSaveInstanceState() method to place the data in the Bundle, and retrieve that data the onActivityCreated() method.

6. Modifying Fragments at runtime

The FragmentManager class and the FragmentTransaction class allow you to add, remove and replace fragments in the layout of your activity.

Fragments can be dynamically modified via transactions. To dynamically add fragments to an existing layout you typically define a container in the XML layout file in which you add a Fragment. For this you can use, for example, a FrameLayout element.

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.your_placehodler, new YourFragment());
ft.commit(); 

A new Fragment will replace an existing Fragment that was previously added to the container.

If you want to add the transaction to the backstack of Android, you use the addToBackStack() method. This will add the action to the history stack of the activity, i.e., this will allow to revert the Fragment changes via the back button.

7. Animations for Fragment transition

During a fragment transaction you can define animations which should be used based on the Property Animation API via the setCustomAnimations() method.

You can also use several standard animations provided by Android via the setTransition() method call. These are defined via the constants starting with FragmentTransaction.TRANSIT_FRAGMENT_*.

Both methods allow you to define an entry animation and an existing animation.

8. Adding Fragments transition to the backstack

You can add a FragmentTransition to the backstack to allow the user to use the back button to reverse the transition.

For this you can use the addToBackStack() method on the FragmentTransition object.

9. Fragments for background processing

9.1. Headless Fragments

Fragments can be used without defining a user interface.

To implement a headless fragment, simply return null in the onCreateView() method of your fragment.

Tip

It is recommended to use headless fragments for your background processing in combination with the setRetainInstance() method. This way you don't have to handle the configuration changes during your asynchronous processing yourself.

9.2. Retained headless fragments to handle configuration changes

Headless fragment are typically used to encapsulate some state across configuration changes or for a background processing task. For this purpose you would set your headless fragment to be retained. A retained fragment is not destroyed during configuration changes.

Retained headless fragment

To set your fragment to retained, call its setRetainInstance() method.

To add such a Fragment to an activity you use the add() method of the FragmentManager class. If you need to refer to this Fragment later, you need to add it with a tag to be able to search for it via the findFragmentByTag() method of the FragmentManager.

Warning

The usage of the onRetainNonConfigurationInstance() is deprecated and should be replaced by retained headless fragments.

10. Fragments Tutorial

10.1. Overview

The following tutorial demonstrates how to use fragments . The application will use layouts with different fragments depending on portrait and landscape mode.

In portrait mode the RssfeedActivity will show one Fragment. From this fragment the user can navigate to another activity which contains another Fragment.

In landscape mode RssfeedActivity will show both fragments side by side.

1. Create Project

Create a new Android project with the following data.

Table 2. Android project

PropertyValue
Application NameRSS Reader
Project Namecom.example.android.rssfeed
Package namecom.example.android.rssfeed
TemplateEmpty Activity
ActivityRssfeedActivity
Layoutactivity_rssfeed


10.2. Create standard layouts

Create or change the following layout files in the res/layout/ folder.

Create a new layout file called fragment_rssitem_detail.xml. This layout file will be used by the DetailFragment.

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

    <TextView
        android:id="@+id/detailsText"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal|center_vertical"
        android:layout_marginTop="20dip"
        android:text="Default Text"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textSize="30dip" />

</LinearLayout> 

Create a new layout file called fragment_rsslist_overview.xml. This layout file will be used by the MyListFragment.

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

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Press to update"
         />

</LinearLayout> 

Change the existing activity_rssfeed.xml file. This layout is the default layout for RssfeedActivity and shows two fragments .

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

    <fragment
        android:id="@+id/listFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:layout_marginTop="?android:attr/actionBarSize"
        class="com.example.android.rssfeed.MyListFragment" ></fragment>

    <fragment
        android:id="@+id/detailFragment"
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="match_parent"
        class="com.example.android.rssfeed.DetailFragment" >
        <!-- Preview: layout=@layout/details -->
    </fragment>

</LinearLayout> 

10.3. Create Fragment classes

Next you create the Fragment classes. Start with the DetailFragment class.

package com.example.android.rssfeed;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class DetailFragment extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rssitem_detail,
        container, false);
    return view;
  }

  public void setText(String item) {
    TextView view = (TextView) getView().findViewById(R.id.detailsText);
    view.setText(item);
  }
} 

Create the MyListFragment class. Despite its name it will not display a list of items. Instead it will just have a button which allow to send the current time to the details fragment.

package com.example.android.rssfeed;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public class MyListFragment extends Fragment {
  
  private OnItemSelectedListener listener;
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rsslist_overview,
        container, false);
    Button button = (Button) view.findViewById(R.id.button1);
    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        updateDetail();
      }
    });
    return view;
  }

  public interface OnItemSelectedListener {
      public void onRssItemSelected(String link);
    }
  
  @Override
    public void onAttach(Activity activity) {
      super.onAttach(activity);
      if (activity instanceof OnItemSelectedListener) {
        listener = (OnItemSelectedListener) activity;
      } else {
        throw new ClassCastException(activity.toString()
            + " must implemenet MyListFragment.OnItemSelectedListener");
      }
    }
  
  
  // May also be triggered from the Activity
  public void updateDetail() {
    // create fake data
    String newTime = String.valueOf(System.currentTimeMillis());
    // Send data to Activity
    listener.onRssItemSelected(newTime);
  }
} 

10.4. RssfeedActivity

Change the RssfeedActivity class to the following code.

package com.example.android.rssfeed;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class RssfeedActivity extends Activity implements MyListFragment.OnItemSelectedListener{

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

    // if the wizard generated an onCreateOptionsMenu you can delete
    // it, not needed for this tutorial

  @Override
  public void onRssItemSelected(String link) {
    DetailFragment fragment = (DetailFragment) getFragmentManager()
            .findFragmentById(R.id.detailFragment);
        if (fragment != null && fragment.isInLayout()) {
          fragment.setText(link);
        } 
  }
    
} 

10.5. Run

Run your example. Both fragments should be displayed both in landscape and portrait mode. If you press the button in the ListFragment, the DetailFragment should get updated.

11. Fragments Tutorial - layout for portrait mode

11.1. Create layouts for portrait mode

The RssfeedActivity should use a special layout file in portrait mode. In portrait mode Android will check the layout-port folder for fitting layout files. If Android does not find a fitting layout file, it uses the layout folder.

For this reason create the res/layout-port folder. Afterwards create the following activity_rssfeed.xml layout file in the res/layout-port folder.

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

    <fragment
        android:id="@+id/listFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?android:attr/actionBarSize"
        class="com.example.android.rssfeed.MyListFragment" />
</LinearLayout> 

Also create the activity_detail.xml layout file. This layout will be used in the DetailActivity. Please note that we could have created this file also in the res/layout folder, but it is only used in portrait mode hence we place it into this folder.

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

    <fragment
        android:id="@+id/detailFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.example.android.rssfeed.DetailFragment" />

</LinearLayout> 

11.2. DetailActivity

Create a new activity called DetailActivity with the following class.

package com.example.android.rssfeed;

import android.app.Activity;
import android.app.Application;
import android.content.res.Configuration;
import android.os.Bundle;

public class DetailActivity extends Activity {
  public static final String EXTRA_URL = "url";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Need to check if Activity has been switched to landscape mode
    // If yes, finished and go back to the start Activity
    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
      finish();
      return;
    }
    setContentView(R.layout.activity_detail);
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
      String url = extras.getString(EXTRA_URL);
      DetailFragment detailFragment = (DetailFragment) getFragmentManager()
          .findFragmentById(R.id.detailFragment);
      detailFragment.setText(url);
    }
  }
} 

Ensure that you also register this activity in the AndroidManifest.xml file.

11.3. Adjust the RssfeedActivity activity

Adjust the RssfeedActivity class to display the DetailActivity in case the other fragment is not present in the layout.

package com.example.android.rssfeed;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;

public class RssfeedActivity extends Activity implements
    MyListFragment.OnItemSelectedListener {

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

  @Override
  public void onRssItemSelected(String link) {
    DetailFragment fragment = (DetailFragment) getFragmentManager()
        .findFragmentById(R.id.detailFragment);
    if (fragment != null && fragment.isInLayout()) {
      fragment.setText(link);
    } else {
      Intent intent = new Intent(getApplicationContext(),
          DetailActivity.class);
      intent.putExtra(DetailActivity.EXTRA_URL, link);
      startActivity(intent);

    }
  }

} 

11.4. Run

Run your example. If you run the application in portrait mode, you should see only one Fragment. Use the Ctrl+F11 shortcut to switch the orientation. In horizontal mode you see two fragments . If you press the button in portrait mode, the a new DetailActivity is started and shows the current time. In horizontal mode you see both fragments .

Screenshot

12. Dynamics Fragments Exercise

12.1. Target

Change the RssReader example so that dynamic fragments are used.

A multi-pane layout should be used in case of a large screen, e.g., tablet. The switch point should be 600dp.

Implement the solution with only one activity with multiple fragments , delete the DetailsActivity at the end of this exercise.

12.2. Use placeholder for the fragments

Replace the static fragments in the layout folders with FrameLayouts as placeholder.

12.3. Use fragment manager to replace fragments

Implement a solution so that you have only one activity and remove the fragments on demand.

13. Support this website

This tutorial is Open Content under the CC BY-NC-SA 3.0 DE license. Source code in this tutorial is distributed under the Eclipse Public License. See the vogella License page for details on the terms of reuse.

Writing and updating these tutorials is a lot of work. If this free community service was helpful, you can support the cause by giving a tip as well as reporting typos and factual errors.

13.1. Thank you

Please consider a contribution if this article helped you.

Flattr this

13.2. Questions and Discussion

If you find errors in this tutorial, please notify me (see the top of the page). Please note that due to the high volume of feedback I receive, I cannot answer questions to your implementation. Ensure you have read the vogella FAQ as I don't respond to questions already answered there.

14. Links and Literature

14.1. Source Code

Source Code of Examples

14.3. vogella Resources

vogella Training Android and Eclipse Training from the vogella team

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java, compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put all your files in a distributed version control system