Android Fragment transaction: FragmentManager and Backstack

Learn how to use Android fragment and how to manage Fragment transaction with a step by step guide

This post describes how to use Android Fragment transaction to handle fragments. Android Fragment are useful when we want to support multiple screen size. To manage fragments we need a FragmentManager that help us to handle  Android fragment trasaction between fragments.  With Android fragment transaction we mean a sequence of steps to add, replace or remove fragments. In the last post we showed how to support multiple screen size and orientation using fragments. Now we want to go a bit further.
If you are not familiar with Fragment i suggest you to read before how to getting started with fragments. It can be useful, if you want to go a bit deeper, read also this tutorial about a real life example of using Fragment with Webview, before digging in the fragment transaction.

[bctt tweet=”Surviving with Android: My source for tutorials, Source code and Open source project in Android”]

In Android there are two different methods to create fragment:

  • static method
  • dynamic method

Static method is when we “write” directly our fragment in XML file.

[xml] <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:paddingBottom=”@dimen/activity_vertical_margin” android:paddingLeft=”@dimen/activity_horizontal_margin” android:paddingRight=”@dimen/activity_horizontal_margin” android:paddingTop=”@dimen/activity_vertical_margin” tools:context=”.MainActivity” android:orientation=”horizontal”>
<fragment android:id=”@+id/listFragment” android:layout_width=”0dp” android:layout_height=”wrap_content” class=”com.survivingwithandroid.fragment.LinkListFragment” android:layout_weight=”2″/>
</LinearLayout>
[/xml]

In this case, our layout isn’t dynamic because we can’t manage the fragment at runtime. So if we want to make our layout dynamic (and this happen very often) we need to do it in another way. We have to use FrameLayout. With FrameLayout we can handle fragments as we need at runtime, but to do it we need a manager, in other words, a component that can handle fragments. This is FragmentManager. This component can add, replace and remove fragments at runtime. The layout above becomes:

[xml] <RelativeLayout 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:paddingBottom=”@dimen/activity_vertical_margin”
android:paddingLeft=”@dimen/activity_horizontal_margin”
android:paddingRight=”@dimen/activity_horizontal_margin”
android:paddingTop=”@dimen/activity_vertical_margin”
tools:context=”.MainActivity” >

<FrameLayout android:id=”@+id/listFragment”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”/>
</RelativeLayout>[/xml]

So now we have all the freedom to “inject” in the FrameLayout our fragments.

Handle Android fragment transaction with FragmentManager

As we said before FragmentManager is the key component. Using FragmentManager we can discover (find) fragment inside our layout using findFragmentById or findFragmentByTag. While the first method is very simple and we use the common android id to discover the component, the second method (that uses tag) is unsual. A tag in a fragment is simply a “name” we give to the fragment so that we can find it later using that name. We are more interested in some other methods.

All the operation that are made by the FragmentManager happens inside a “transaction” (for that Android fragment transaction) like in a database operation. First, we can get the FragmentManger using the Activity method getFragmentManager(). Once we have the reference to this component we have to start the transaction in this way:

[java]FragmentManager fm = getFragmentManager();

// Transaction start
FragmentTransaction ft = fm.beginTransaction();
…….
// Transaction commit
ft.commit();[/java]

At the end when we finished and we are ready to show our fragment we have to call the commit method that marks the end of the transaction. For example, if we remember the example we showed in the last post, and using a FrameLayout we can “insert” the link list in this way:

[java]public class MainActivity extends Activity implements ChangeLinkListener{

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

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();

LinkListFragment llf = new LinkListFragment();
ft.replace(R.id.listFragment, llf);
ft.commit();
}

}[/java]

But…What kind of operation we can perform inside the Android fragment transaction?…Well we can:

  • add a new fragment
  • replace an existing fragment
  • remove a fragment

If we remember the example we used last time every time a user clicks on a link the interface method onLinkChange is called. So in this method, we want to show how to perform the operation listed above.

[java]if (findViewById(R.id.fragPage) != null) {
WebViewFragment wvf = (WebViewFragment) getFragmentManager()
.findFragmentById(R.id.fragPage);

// Part 1: Tablet and so on
if (wvf == null) {
System.out.println(“Dual fragment – 1”);
wvf = new WebViewFragment();
wvf.init(linkData.getLink());
// We are in dual fragment (Tablet and so on)
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//wvf.updateUrl(link);
ft.add(R.id.fragPage, wvf);
ft.commit();
}
else {
Log.d(“SwA”, “Dual Fragment update”);
wvf = new WebViewFragment();
wvf.init(linkData.getLink());
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragPage, wvf);
ft.commit();

//wvf.updateUrl(linkData.getLink());
}
}
else {
Log.d(“SwA”, “replace”);
FragmentTransaction ft = getFragmentManager().beginTransaction();
WebViewFragment wvf = new WebViewFragment();
wvf.init(linkData.getLink());
ft.replace(R.id.listFragment, wvf);
ft.commit();
}[/java]

If you compare this piece of code with the last example in the previous post you notice some differences. First, in the green part, we don’t start an activity anymore when the user clicks on a link but we simply replace the FrameLayout with a fragment showing the web page. Moreover, in the yellow part we don’t update the current fragment inside the FrameLayout but we create a new fragment and we replace the existing fragment with the one just created. The app behavior is always the same but we obtained this behavior in a different way, using dynamic fragments inside our layout.

If you run the app and start using it you can notice a “wired” behavior when you press the back button. We’d expect that the back button would bring us to the last web page visited but it isn’t like we supposed. When you press back button you come to the homepage.

android fragment tutorial

android fragment example

fragments in android

Why?

Fragment Backstack

Well the behavior described above is normal because the back button acts at activity level, not at the fragment level. So our activity is the same while we replace fragments as the user interacts with the app. In this way when we tap on the back button we select the first activity on the activity stack, in our case the home. We don’t want this behavior but we want that when we click on the back button we go back in the fragments stack. We can achieve it adding the fragment to the backstack. We do it in this way:

[java]@Override
public void onLinkChange(LinkData linkData) {
System.out.println(“Listener”);
// Here we detect if there’s dual fragment
if (findViewById(R.id.fragPage) != null) {
WebViewFragment wvf = (WebViewFragment) getFragmentManager()
.findFragmentById(R.id.fragPage);

if(wvf == null) {
System.out.println(“Dual fragment – 1”);
wvf = new WebViewFragment();
wvf.init(linkData.getLink());
// We are in dual fragment (Tablet and so on)
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//wvf.updateUrl(link);
ft.add(R.id.fragPage, wvf);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// Add to backstack
ft.addToBackStack(linkData.getName());
ft.commit();
}
else {
Log.d(“SwA”, “Dual Fragment update”);
wvf = new WebViewFragment();
wvf.init(linkData.getLink());
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragPage, wvf);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// Add to backstack
ft.addToBackStack(linkData.getName());
ft.commit();

//wvf.updateUrl(linkData.getLink());
}
}
else {
Log.d(“SwA”, “replace”);
FragmentTransaction ft = getFragmentManager().beginTransaction();
WebViewFragment wvf = new WebViewFragment();
wvf.init(linkData.getLink());

ft.addToBackStack(linkData.getName());
ft.replace(R.id.listFragment, wvf);
ft.commit();
}

}[/java]

We use the addToBackStack method of the FragmentTrasaction and we add every fragment to the backstack. In this way when we tap the back button we have the correct behavior. In this post, you learned how to handle Android fragment transaction and how to manage fragments.

    1. Joaquim Silva September 4, 2013
    2. survivingwithandroid September 4, 2013
    3. Rahul September 30, 2013
    4. Sharon October 30, 2013
    5. frostymarvelous June 24, 2014
    6. Prince July 17, 2014
    7. Kavitha October 13, 2014
      • frostymarvelous October 18, 2014
    8. Kavitha October 13, 2014
    9. frostymarvelous October 18, 2014
    10. Moorthi November 1, 2014
    11. Moorthi November 1, 2014
    12. Gökhan KURT January 13, 2015
    13. Gökhan KURT January 12, 2015
    14. Ulhas Patil April 1, 2015
      • Divyesh Kalotra November 8, 2017
    15. Toni June 8, 2016
      • Divyesh Kalotra November 8, 2017
    16. Lőrincz Áron February 14, 2017
    17. Armando Marques Sobrinho March 20, 2017
    18. Francesco Azzola June 20, 2017

    Add Your Comment