Support free tutorials





Quick links

Multi-pane development in Android with Fragments - Tutorial

Lars Vogel

Version 11.6

13.09.2015

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 Android 5.0.


Table of Contents

1. Android Basics
2. Fragments
2.1. What are single-pane or multi-pane layouts?
2.2. What are fragments?
2.3. Fragments and Context access
2.4. Advantages of using fragments
2.5. How to support different screensizes with fragments
3. Defining and using fragments
3.1. Defining fragments
3.2. Application communication with fragments
4. Fragment life-cycle
5. Defining fragments for your activity
5.1. Adding fragments statically to the layout file
5.2. Handling dynamics in fragments
5.3. Check if a fragment is present in the layout
5.4. Determine how many fragments are present
6. Adding fragments transition to the backstack
7. Animations for fragment transitions
8. Persisting data in fragments
8.1. Persisting data between application restarts
8.2. Persisting data between configurations changes
9. Fragments for background processing
9.1. Headless Fragments
9.2. Retained headless fragments to handle configuration changes
10. Fragments Tutorial
10.1. Target of this exercise
10.2. Create Project
10.3. Remove compatibility layer
10.4. Create standard layouts
10.5. Create fragment classes
10.6. Change the main layout file
10.7. RssfeedActivity
10.8. Validating
11. Exercise: Use different number of fragments depending on the configuration
11.1. Create layouts for portrait mode
11.2. Define a boolean flag dependent of the resource selector
11.3. Create class for new activity
11.4. Register new class as activity via the manifest
11.5. Adjust the RssfeedActivity activity
11.6. Validate your implementation
12. Exercise: Dynamic replacement of fragments depending on the configuration
12.1. Target
12.2. Use placeholder for the layout files
12.3. Define a variable to determine if you are in single or dual pane mode
12.4. Use fragment manager to replace fragments
13. References
13.1. Create an image via Android studio
13.2. Creating a resource folder
13.3. Creating a resource file
13.4. Add a new menu XML resource
13.5. Remove the usage of the support library
14. About this website
15. Links and Literature
15.1. Android Resources
15.2. vogella GmbH training and consulting support

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 single-pane or multi-pane layouts?

Android devices exists in a variaty of screen sizes and densities.

A panel or pane represents a part of the user interface. The term pane is a general term used to describe the concept that multiple views are combined into one compound view depending on the actual available space.

Panel

If not enough space is available only one panel is shown. This is typically called a single-pane layout.

Panel

If more space is available, multiple panels can be shown.

Panel

2.2. What are fragments?

A fragment is an independent Android 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.

2.3. Fragments and Context access

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

2.4. Advantages of using fragments

Fragments simplify the reuse of 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.

As it is possible to dynamically add and remove fragments from an activity, the usage of fragments allows to design very flexible user interfaces.

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.5. How to support different screensizes with fragments

It is possible to define in the layout file of an activity that it contains fragments (static definition) or to modify the fragments of an activity at runtime (dynamic definition).

To display different fragments in your activities based on the actual available space you can:

  • Use one activity, which displays two fragments for tablets and on handset devices. In this case change at runtime the fragments displayed by the activity whenever necessary. In this scenario you typically define instances of the FrameLayout class as placeholder in your layout and add the fragments at runtime to them.

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

Which option to select depends on the use case, typical the dynamic contribution is more flexible bit a bit harder to implement.

3. Defining and using fragments

3.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.rssreader;

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 url) {
    TextView view = (TextView) getView().findViewById(R.id.detailsText);
    view.setText(url);
  }
} 

3.2. 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.rssreader;

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("fake");
      }
    });
    return view;
  }

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

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

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

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

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

4. Fragment life-cycle

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

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

Fragment lifecycle

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

Table 1. Fragment life-cycle

Method Description
onAttach() The fragment instance is associated with an activity instance.The fragment and the activity is not fully initialized. Typically you get in this method a reference to the activity which uses the fragment for further initialization work.
onCreate() Fragment is created. The onCreate() method is called after the onCreate() method of the activity but before the onCreateView() method of the fragment.
onCreateView()

The fragment instance creates its view hierarchy. In the onCreateView() method the fragment creates 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.

In this method you should not interactive with the activity, the activity is not yet fully initialized.

There is no need to implement this method for headless fragments.The inflated views become part of the view hierarchy of its containing activity.

onActivityCreated()

The onActivityCreated() is called after the onCreateView() method when the host activity is created. Activity and fragment instance have been created as well as the view hierarchy of the activity. At this point, view can be accessed with the findViewById() method. example.

In this method you can instantiate objects which require a Context object.

onStart() The onStart() method is called once the fragment gets visible.
onResume() Fragment becomes active.
onPause() Fragment is visible 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.
onDestroyView() Destroys the view of the fragment. If the fragment is recreated from the backstack this method is called and afterwards the onCreateView method.
onDestroy() Not guaranteed to be called by the Android platform.

5. Defining fragments for your activity

5.1. Adding fragments statically to the layout file

To use your new fragment, you can statically add it to an XML layout. In this case the android:name attribute points to the corresponding class as demonstrated by the following code snippet.

<?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:baselineAligned="false"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/listFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        class="com.example.android.rssreader.MyListFragment" ></fragment>
    <fragment
        android:id="@+id/detailFragment"
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="match_parent"
        class="com.example.android.rssreader.DetailFragment" >
    </fragment>

</LinearLayout> 

Using this scenario makes sense in case you have different static layout files for different device configurations.

5.2. Handling dynamics in fragments

The class which can be access in the activity via the getFragmentManager() method allows you to add, remove and replace fragments in the layout of your activity.

The modifications must be performed in a transaction via the FragmentTransaction class.

To modify the fragments in an activity you typically define a FrameLayout placeholder in the layout file.

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

    <FrameLayout
        android:id="@+id/listcontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <FrameLayout
        android:id="@+id/detailscontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />

</LinearLayout> 

You use the FragmentManager to replace the container with a fragment.

// get fragment manager
FragmentManager fm = getFragmentManager();

// add
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.your_placehodler, new YourFragment());
// alternatively add it with a tag
// trx.add(R.id.your_placehodler, new YourFragment(), "detail");
ft.commit();

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

// remove
Fragment fragment = fm.findFragmentById(R.id.your_placehodler);
FragmentTransaction ft = fm.beginTransaction();
ft.remove(fragment);
ft.commit(); 

A new fragment replaces an existing fragment in this 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.

5.3. Check if a fragment is present in the layout

To check if the fragment is part of your layout you can use the FragmentManager class. The isInLayout() method works on if the fragment as added to the activity via its layout.

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

5.4. Determine how many fragments are present

As the logic in the activity depends on the scenario (single/multi pane), you typically write a check after setting the layout in the activity to check if in this mode you are. There are several approaches to perform this. One way is to define a configuration file in the values resource folder of you project with a key / value pair defaulting to false and additional configuration files for the different configurations setting this value to true.

For example this is a possible default config.xml configuration file.

<resources>
    <item type="bool" name="dual_pane">false</item>
</resources> 

For example in the values-land folder you would place config.xml configuration file with a different value.

<resources>
    <item type="bool" name="dual_pane">true</item>
</resources> 

In your code you can access the state via the following snippet.

getResources().getBoolean(R.bool.dual_pane); 

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

7. Animations for fragment transitions

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. Persisting data in fragments

8.1. Persisting data between application restarts

Frequently in your Android application you need to persist your application data. For this, you can for example use an SQLite database or a file.

8.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 fragment. This retains fragment instances between configuration changes but only works if the fragments are not added to the backstack. In this case the data must be stored as member (field).

Note

Using this method is not recommended by Google for fragments which have a user interface. See Section 9.1, “Headless Fragments”.

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.

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 services for background processing. If you want to do this via your fragments, the second best solution is to use headless fragments 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.

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

10. Fragments Tutorial

10.1. Target of this exercise

The following tutorial demonstrates how to use fragments in a standard Android application without using the support library. The application uses 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.

10.2. Create Project

Create a new Android project with the following data.

Table 2. Android project

Property Value
Application Name RSS Reader
Company Domain android.example.com
Package name com.example.android.rssreader
Template Empty Activity
Activity RssfeedActivity
Layout activity_rssfeed


10.3. Remove compatibility layer

Remove any reference to the compatibility layer so simplify the generated example. See Section 13.5, “Remove the usage of the support library” for the process of doing this.

10.4. Create standard layouts

Create 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 is 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> 

10.5. Create fragment classes

Create the follows classes which are used as fragments. Start with the DetailFragment class.

package com.example.android.rssreader;

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 url) {
    TextView view = (TextView) getView().findViewById(R.id.detailsText);
    view.setText(url);
  }
} 

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.rssreader;

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("fake");
      }
    });
    return view;
  }

  public interface OnItemSelectedListener {
      public void onRssItemSelected(String link);
    }
  
  @Override
    public void onAttach(Context context) {
      super.onAttach(context);
      if (context instanceof OnItemSelectedListener) {
        listener = (OnItemSelectedListener) context;
      } else {
        throw new ClassCastException(context.toString()
            + " must implement MyListFragment.OnItemSelectedListener");
      }
    }
  
  // triggers update of the details fragment
  public void updateDetail(String uri) {
    // create fake data
    String newTime = String.valueOf(System.currentTimeMillis());
    // send data to activity
    listener.onRssItemSelected(newTime);
  }
} 

10.6. Change the main layout file

Change the existing activity_main.xml file.

<?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:baselineAligned="false"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/listFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        class="com.example.android.rssreader.MyListFragment" ></fragment>
    <fragment
        android:id="@+id/detailFragment"
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="match_parent"
        class="com.example.android.rssreader.DetailFragment" >
    </fragment>

</LinearLayout> 

10.7. RssfeedActivity

Change the RssfeedActivity class to the following code.

package com.example.android.rssreader;

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_main);
    }

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

} 

10.8. Validating

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

First result

11. Exercise: Use different number of fragments depending on the configuration

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.

Create the following activity_main.xml layout file based on the port resource qualifier for orientation. See Section 13.3, “Creating a resource file” for information how to do this.

<?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"
        class="com.example.android.rssreader.MyListFragment" />
</LinearLayout> 

Also create a new layout file called activity_detail.xml. This layout will be used by an activity which shows the detailed fragment in portrait mode. 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.rssreader.DetailFragment" />

</LinearLayout> 

11.2. Define a boolean flag dependent of the resource selector

Create a file in your res/values folder called config.xml with the following setting.

<resources>
    <item type="bool" name="dual_pane">false</item>
</resources> 

Create the same file in your res/values-land folder with a different value.

<resources>
    <item type="bool" name="dual_pane">true</item>
</resources> 

11.3. Create class for new activity

Create a new activity called DetailActivity with the following class.

package com.example.android.rssreader;

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);

    // check if dual pane mode is active
    // if yes, finish this activity
    if (getResources().getBoolean(R.bool.twoPaneMode)) {
      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);
    }
  }
} 

11.4. Register new class as activity via the manifest

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.rssreader" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".RssfeedActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".DetailActivity"
            android:label="@string/app_name" >
        </activity>
    </application>

</manifest> 

11.5. 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.rssreader;

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_main);
    }

    @Override
    public void onRssItemSelected(String link) {
      boolean dual_pane = getResources().getBoolean(R.bool.dual_pane);
        if (dual_pane) {
             DetailFragment fragment = (DetailFragment) getFragmentManager()
                .findFragmentById(R.id.detailFragment);
            fragment.setText(link);
        } else {
            Intent intent = new Intent(getApplicationContext(),
                    DetailActivity.class);
            intent.putExtra(DetailActivity.EXTRA_URL, link);
            startActivity(intent);

        }
    }

} 

11.6. Validate your implementation

Test your application. If you run the application in portrait mode, you should see only one fragment. In horizontal mode you see both fragments.

Use the Ctrl+F11 shortcut to switch the orientation. Press the button in portrait as well as in horizontal mode and verify that the detail activity shows the current time.

Screenshot

12. Exercise: Dynamic replacement of fragments depending on the configuration

12.1. Target

In this exercise you use the FragmentManager to dynamically add fragments to your activity.

After you implement this exercise you end up with only one activity and you can delete the DetailsActivity at the end of this exercise.

12.2. Use placeholder for the layout files

Replace the static fragments in the layout folders with FrameLayouts as placeholder. The following listing is the entry for the res/layout folder. In this layout the second container is defined to be unused (gone).

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

    <FrameLayout
        android:id="@+id/listcontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <FrameLayout
        android:id="@+id/detailscontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />

</LinearLayout> 

The following listing is the entry for the res/layout-land 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="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        class="com.example.android.rssreader.MyListFragment" />
    
    <fragment
        android:id="@+id/detailFragment"
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="match_parent"
        class="com.example.android.rssreader.DetailFragment" />

</LinearLayout> 

12.3. Define a variable to determine if you are in single or dual pane mode

Create the following res/values/config.xml configuration file.

<resources>
    <item type="bool" name="dual_pane">false</item>
</resources> 

In the res/values-land folder place the config.xml configuration file with a different value.

<resources>
    <item type="bool" name="dual_pane">true</item>
</resources> 

12.4. Use fragment manager to replace fragments

Implement a solution so that you have only one activity which handles the fragments on demand.

activity_rssfeed.xml
activity_rssfeedland.xml
replace.java
RssfeedActivity.java 

13. References

13.1. Create an image via Android studio

See Creating an image asset to learn how to create an image asset with Android Studio.

13.2. Creating a resource folder

See Creating a new resource folder to learn how to a new resource file with Android Studio.

13.3. Creating a resource file

See Creating a new resource file to learn how to a new resource file with Android Studio.

13.4. Add a new menu XML resource

See Add a new menu XML resource to learn how to a new XML menu resource with Android Studio.

13.5. Remove the usage of the support library

See Android support library how to remove the usage of the support library.

14. About this website

15. Links and Literature

15.2. vogella GmbH training and consulting support

TRAINING SERVICE & SUPPORT
The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”. The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers.