Android ,Working with Fragments.

android_proud_iconIf you know what an activity is in android ,then you have probably crossed paths with the Fragment concept.The android documentation defines it as a behavior or a portion of user interface in an Activity .It is a stripped down version of an activity that can handle its own lifecycle events but that still needs an activity to host it.I have found a lot of examples that explain how to use fragments but none was focused enough to cover the features I need the most like static fragments ,dynamic fragments ,communication between fragments(all in one project) and the pitfalls one comes across when using them in a real project.That s why I decided to make this tutorial that just does that.Lets get going.

The Design.

We wish to have two fragments in our design.Those are shown in the figure below.First we will stuff then inside an activity layout statically and try to think about the benefits and practical usages of that.Then we are going to dynamically add those fragments to the activity and wire them up so that clicking on one button in Fragment1 causes Fragment1 to be replaced by Fragment2 and Fragment2 showing which button as pressed in Fragment1.With this design we will know about the following

(1) .Creating the Fragment classes.

(2) .Loading layouts in Fragments

(3) Adding fragments statically to the layout

(4) Adding fragments dynamically to the layout

(5) Communication between Fragments though the host activity.

android_fragment_design

Creating the Project and Fragment Classes.

Create a new Android Studio project and name it FragmentsTute.We have shown how to create a new project with an empty activity in a previous tutorial.Your project should look something like the figure below.

android_fragments_tute_project

We have a MainActivity.java file and its layout file : activity_main.xml.

Fragment Implementations in Android.

In android there are two implementations of fragments(I might be wrong here).In the figure below I have imported both of them on purpose just to make a point.The system is clearly telling me there is something wrong as I am not supposed to import both implementations at the same time.So how are those different?

android_fragment_dilema

android.app.Fragment implementation is built into the android operating system .From a developer perspective ,all you need is to add the import statement in your .java files and you can use them right away.As the code to manage the fragments lives in the android OS ,your app is not responsible for managing fragments.This results in smaller apk files.

To use the support.v4. version of the fragments ,simply adding the import will not work.You need to add the support library as a dependency of your application.In other words you download the support.v4 library to be part of your apk.This results in bigger apk sizes obviously.Now why would I use support.v4 in my apps?Well the support libraries allow for older android devices to support new features that are introduced after they are released.

I like the flexibility of having older devices support new cool features so I will use the support.v4 version of the Fragments.We need to add the support.v4 dependency as we have mentioned above.Click on File and select Project Structure as shown in the figure below.

android_fragments_project_structure

Click on app and choose the dependencies tab.Hit the green plus sign and select support.v4.Hit OK and OK again and Android Studio should be busy loading your library.Note that these steps may change in the future as android studio is updated frequently but the flow should stay the same for some foreseeable future.

Creating Fragment classes and Layouts.

Create a new Java class and name it Fragment1.My fresh new class is shown below:

package com.blikoon.fragmentstute;

import android.support.v4.app.Fragment;

/**
 * Created by gakwaya on 2/13/2016.
 */
public class Fragment1 extends Fragment {
   
}

You can notice that it a subclass of Fragment ,the android.support.v4.app version.There are methods you need to implement in fragment subclasses to enable them to do some things.One of these methods is onCreateView.Android uses this method in the Fragment to load the UI layout file that the fragment is going to display.The code snipped below shows my Fragment1 class with the onCreateView method implemented.

package com.blikoon.fragmentstute;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by gakwaya on 2/13/2016.
 */
public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstancestate)
    {
        return inflater.inflate(R.layout.fragment1,container,
                false);
    }

}

The method returns a View object which is like a wrapper box that contains the view objects(buttons in our case) in the layout file.It takes three arguments.The first is a LayoutInflater object.We use this object to take a layout.xml file and turn it into classes instances wrapped in the View that we return from this function.We will not say more about the other arguments as the details would take us off topic.We’ll talk about them when they are needed.In the body of the function we load the layout file.

return inflater.inflate(R.layout.fragment1,container,
        false);

fragment1 is the name of the layout file to load.It’s not there yet .So we create it next.Right click on the res->layout folder and choose New->Layout resource file.Name yours fragment1 and hit ok.My resulting layout file is shown below.If you have trouble creating these files ,we have gone through the needed details in a previous tutorial.

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

</LinearLayout>

Now we need to add the buttons.Remember from our design section that we need to add 4 buttons to Fragment1.The layout file with the buttons added looks as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button1"/>
    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button2"/>
    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button3"/>
    <Button
        android:id="@+id/button4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button4"/>

</LinearLayout>

They are wrapped inside a vertical LinearLayout.The preview of the fragment looks as shown is the figure below:

android_fragment1_preview

This is what I had in mind.Now following the same steps we can create the Fragment2 class.The android studio screen looks as follows after I create it.

android_fragment2_java

Notice that fragment2 is in red and the red underlines on java classes in the left pane.This is Android Studio’s way to tell you that something is wrong.In our case ,we are loading a layout file that we have not created yet.Add the layout file and name it fragment2.Mine is shown below:

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

</LinearLayout>

In our design ,Fragment2 contains a TextView and a Button.Add them and your fragment2.xml file should look like this :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
        android:id="@+id/info_text_view"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:hint="info shown here"
        android:background="#bba0a0"
        android:gravity="center_vertical|center_horizontal"/>
    <Button
        android:id="@+id/back_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Back"/>

</LinearLayout>

The TextView has a few attributes you may have not seen before.The layout_height has a fixed value of 40 dp as it looked ugly with the usual wrap_content value.We also added a background to it.The hint is a piece of text that shows how our text view looks but that text is not shown at run time.Finaly ,the android:gravity attributes controls where text is shown within our textView.The preview of the fragment layout is shown below:

android_fragment2_preview

Loading Fragments Statically inside an Activity.

Our fragments are ready .Now we want to show both of them inside MainActivity when our application starts up.MainActiviy and its layout file are reproduced below for convenience.

android_fragments_tute_project

You probably know that android activities load their layout files from their onCreate() method.The layout file is activity_main.xml.Its contents are shown below.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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="com.blikoon.fragmentstute.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"/>
</RelativeLayout>

To add the fragments instead of the currently boring TextView,simply remove the text view and add fragment tags and instruct them to load the fragments that we have created previously through the android:name attribute.The results are shown below:

<?xml version="1.0" encoding="utf-8"?>
<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="com.blikoon.fragmentstute.MainActivity">

    <fragment
        android:id="@+id/fragment1"
        android:name="com.blikoon.fragmentstute.Fragment1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <fragment
        android:id="@+id/fragment2"
        android:layout_below="@id/fragment1"
        android:name="com.blikoon.fragmentstute.Fragment2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</RelativeLayout>

The RelativeLayout is used here and you can see that fragment2 is positioned relatively to fragment1.Whe you try to preview the activity layout file with the fragments loaded ,it simply shows that the layout contains fragments but the contents are not shown.

android_fragments_activity_preview

To really see the looks of your design you need to run the app on a real device ,or a virtual device.Mine is shown below running on my android phone.

android_phone_fragment_preview

This is exactly what we expected.The first fragment ,which contains four buttons is shown on top and the second fragment with a textView and a button right at the bottom.I hope this illustrates that fragments are a tool you have as an android developer to build independent (to some extent) sections of your user interface.Our Fragments for the moment are staticaly hosted inside the activity.

Now how is useful?The snenario I have seen with this used most is for designing flexible user interfaces that can be used both on phones and tablets.A scenario illustrated in the figure below.(Image from :http://developer.android.com/images/fundamentals/fragments.png)

fragments

In the figure,FragmentA contains a list of items and FragmentB contains the details of an item.On a tablet ,which has enough space to show them all at once ,they are shown side by side.On a phone however ,we show them in different activities:when a user clicks on one item ,we start another activity that contains the detail fragment FragmentB.This can easily be achieved by creating different layout files.Namely layout_tablet.xml : which contains the two fragments side by side and layout_phone.xml which only shows the FragmetA on the phone.

There sure other uses for this design.Basicaly ,whenever you have a piece of user interface that you think you can use somewhere else in your app ,it is a good idea to wrap it into a fragment so that when you need it you just stuff it into an activity .Its that cool 😉 .

Adding Fragments to an Activity Dynamically.

Static fragments stuffed inside an activity are cool.But sometimes you need to have the flexibility of replacing or exchanging fragments inside a placeholder in an activity layout file.That’s where dynamic fragments come in.To use dynamic fragments you really need to do two things:

(1) Define a placeholder for the fragment in the activity layout file

(2) Get a reference to the placeholder in the activity .java file and …..add the fragment.

Lets just do that.Go back to the activity_main.xml file of your project and delete the fragments we have added.Yes!We’re going dynamic and we don’t need’em anymore.The file should look like this:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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="com.blikoon.fragmentstute.MainActivity">


  
</RelativeLayout>

We will use FrameLayout as our placeholder.Add a FrameLayout tag to your activity layout file as shown below.

<?xml version="1.0" encoding="utf-8"?>
<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="com.blikoon.fragmentstute.MainActivity">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
  
</RelativeLayout>

That’s all we have to do in the layout file.In the MainActivity.java file ,we want to add Fragment1 to our placeholder.I’ll show you the code that does that and then explain it.

MainActivity.java

package com.blikoon.fragmentstute;

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v4.app.Fragment;

public class MainActivity extends AppCompatActivity {

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

        //Load the Fragment in the place holder
        if(findViewById(R.id.fragment_container) != null)
        {
            Fragment1 fragment1 = new Fragment1();

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            transaction.add(R.id.fragment_container, fragment1);
            transaction.commit();
        }
    }
}

First we check that fragment_container ,the id of our placeholder is correctly detected.Only on successful detection ,do we add the fragment to the placeholder.This is a check you should do to any object before you use it as working on null objects usually causes your application to crash .

To be able to manipulate a the fragment inside a placeholder at run time, you need a reference to a FragmentTransaction object.A transaction is a set of operations you do on the placeholder like adding ,removing and repacing a fragment.The API to get it from the android system is :

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

This API is specific to when you are using fragments from the support.v4.app library.The API when you are using android.app is similar but not necessarily the same.To add the fragment to the place holder you call the add method on the transaction passing in a reference to the id of the placeholder and the fragment you want to add.When done ,call commit on the transaction object and your fragment can be displayed.

transaction.add(R.id.fragment_container, fragment1);
transaction.commit();

Similarly to the static fragments as we have seen before ,it is not currently possible to preview an activity layout file that contains fragments.You need to run your app to see the effect.My activity looks like the figure shown below.

android_fragment_dynamic_fragment1

Communication Between Fragments.

We’re making good progress on our design.The four buttons from Fragment1 are displaying correctly.Remember that we want that when a button is clicked in Fragment1 ,we want for Fragment2 to be shown with a message about the button that was clicked in Fragment1?For that to happen the buttons in Fragment1 need to respond to click events.We get a reference to the buttons in Fragment1.java and set ClickListeners on them as shown in the code snippet below.

Fragment1.java

package com.blikoon.fragmentstute;

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

/**
 * Created by gakwaya on 2/13/2016.
 */
public class Fragment1 extends Fragment {
    Button button1;
    Button button2;
    Button button3;
    Button button4;
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstancestate)
    {
        View v = inflater.inflate(R.layout.fragment1,container,
                false);
        button1 = (Button) v.findViewById(R.id.button1);
        button2 = (Button) v.findViewById(R.id.button2);
        button3 = (Button) v.findViewById(R.id.button3);
        button4 = (Button) v.findViewById(R.id.button4);
        
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        
        
        return v;
    }

}

Notice that we have kept a reference to the View object instead of directly returning it as we did before.

View v = inflater.inflate(R.layout.fragment1,container,
        false);

Then we use a reference to the view to get a reference to the buttons.That is because we can not call findViewById directly from a fragment.You need to use a view object.

button1 = (Button) v.findViewById(R.id.button1);

After that we set click listeners to the buttons so we know when they have been pressed.

button1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
//You can add a log statement here to test your listeners.

    }
});

Now when a user clicks on the buttons our listeners should be called .You can test this by putting debug log statements inside the listener as shown above.I let you practice on that.

We need a way to let Fragment2 know that a button has been clicked in Fragment1 and more importantly ,which button was clicked .To do that we need to know that in android fragments do not communicate directly.Communication between fragments happens through the host activity.In other words ,Fragment1 sends the message to the host activity and then the host activity passes the message to Fragment2.We wire our fragments for communication in these two steps.

Fragment1 talking to host activity.

Android has designed for this communication to happen through interfaces.More specifically ,Fragment1 declares an interface and the host activity must implement that interface.When something happens and Fragment1 wants to notify the host activity ,it simply calls a method that the interface implements.This will make more sense in code.The code snipped below shows Fragment1.java with the interface decalred.

Fragment1.java

package com.blikoon.fragmentstute;

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

/**
 * Created by gakwaya on 2/13/2016.
 */
public class Fragment1 extends Fragment {
    //Declare the interface
    OnFragment1ClickListener mCallback;

    Button button1;
    Button button2;
    Button button3;
    Button button4;


    //Host activity must implement this interface.
    public interface OnFragment1ClickListener
    {
        public void onFragment1Message( String message);

    }

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);

        try
        {
            mCallback = (OnFragment1ClickListener)activity;

        }catch(ClassCastException e)
        {
            throw new ClassCastException(activity.toString() +
                    " must Implement OnFragment1ClickListener");
        }

    }

    
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstancestate)
    {
        View v = inflater.inflate(R.layout.fragment1,container,
                false);
        button1 = (Button) v.findViewById(R.id.button1);
        button2 = (Button) v.findViewById(R.id.button2);
        button3 = (Button) v.findViewById(R.id.button3);
        button4 = (Button) v.findViewById(R.id.button4);

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });


        return v;
    }

}

The interface is declared as follows:

OnFragment1ClickListener mCallback;

and defined to require classes that implement it to define the onFragment1Message() function.

//Host activity must implement this interface.
public interface OnFragment1ClickListener
{
    public void onFragment1Message( String message);

}

And when an activity is trying to use this fragment in the onAttach() method of the fragment.We check that the host activity has implemented the required method.If not we throw an exception.

public void onAttach(Activity activity)
{
    super.onAttach(activity);

    try
    {
        mCallback = (OnFragment1ClickListener)activity;

    }catch(ClassCastException e)
    {
        throw new ClassCastException(activity.toString() +
                " must Implement OnFragment1ClickListener");
    }

}

If your Java programming is rusty and you don’t understand interfaces that well,this shouldn’t really put you off .You can just look at the pattern used here and you will be just fine getting your fragments to communicate.Again you:

(1) .Declare the interface

(2).Define it to require some method(s) implemetation

(3) Check that the Interface has been implemented in the fragment’s onAttach() method.

Our interface is in place.Now we can call mCallback’s onFragment1Message() method indicating which button has been clicked.The relevant part of Fragment1.java is shown below

button1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mCallback.onFragment1Message("Button1");
    }
});
button2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mCallback.onFragment1Message("Button2");
    }
});
button3.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mCallback.onFragment1Message("Button3");
    }
});
button4.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mCallback.onFragment1Message("Button4");
    }
});

The interface mechanism in java allows to call methods implemented in other classes from the class that defines the interface.In our case ,we can call the method onFragment1Message() that MainActivity is going to implement.That is how communication is achieved.We call onFragment1Message() passing information inside the argument.We are done with Fragment1.Going to MainActivity.java we simply implement the interface as shown below.

package com.blikoon.fragmentstute;

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;

public class MainActivity extends AppCompatActivity
implements  Fragment1.OnFragment1ClickListener{

    public void onFragment1Message( String message)
    {
        Log.d("FragmentsTute",message + " Clicked");
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Load the Fragment in the place holder
        if(findViewById(R.id.fragment_container) != null)
        {

            //Should check for savedInstancestate but leave it for now.
            Fragment1 fragment1 = new Fragment1();

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            transaction.add(R.id.fragment_container, fragment1);
            transaction.commit();

        }
    }
}

We declare that the activity implements Fragment1’s inFragment1ClickListener:

public class MainActivity extends AppCompatActivity
implements  Fragment1.OnFragment1ClickListener

and implement the required method:

public void onFragment1Message( String message)
{
    Log.d("FragmentsTute",message + " Clicked");
}

The method prints a log message saying which button was clicked.Run your app ,click on the buttons to see that your MainActivity is notified.My run session on my Genymotion virtual device is shown below.

android_fragment_log_out

Fragment1 is succesfully talking to the host activity ,now we can worry about getting Fragment2 to replace Fragmet1 in the placeholder and passing the message along.

MainActivity activating Fragment2 and passing the message .

When user clicks a button in Fragment1 ,we need to replace Fragment1 by Fragment2 in the placeholder and let Fragment2 know which button was clicked.Replacing a fragment is really a piece of cake now that we know how to add a fragment in the placeholder.In the method onFragment1Message(String ) of MainActivity,instead of simply printing log messages ,we are going to replace Fragment1 by Fragment 2 as shown below.

package com.blikoon.fragmentstute;

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;

public class MainActivity extends AppCompatActivity
implements  Fragment1.OnFragment1ClickListener{

    public void onFragment1Message( String message)
    {

        Fragment2 fragment2 = new Fragment2();
        Bundle args = new Bundle();
        args.putString("fragment1_message",message);
        fragment2.setArguments(args);


        FragmentTransaction transaction =
                getSupportFragmentManager().beginTransaction();

        transaction
                .replace(R.id.fragment_container, fragment2);
        transaction.commit();
    }

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

        //Load the Fragment in the place holder
        if(findViewById(R.id.fragment_container) != null)
        {

            //Should check for savedInstancestate but leave it for now.
            Fragment1 fragment1 = new Fragment1();

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            transaction.add(R.id.fragment_container, fragment1);
            transaction.commit();

        }
    }
}

The code hightlighted in blue is new and deserves an explanation.

Bundle args = new Bundle();
args.putString("fragment1_message",message);
fragment2.setArguments(args);

In short the purpose of this piece of code is pass an extra piece of information to the fragment so that that info can be used by the fragment the moment is displayed on screen.In our case ,we want to let Fragment2 know which Button from Fragment1 the user has clicked.You create a Bundle object , call methods to stuff information inside that bundle and attach that Bundle to the fragment right before it replaces the old one .Replacing Fragment1 by Fragment2 couldn’t be easier!

FragmentTransaction transaction =
        getSupportFragmentManager().beginTransaction();

transaction
        .replace(R.id.fragment_container, fragment2);
transaction.commit();

Simply call replace on the transaction object and pass in fragment2.If you run you app and click on any button ,fragment2 should be displayed as shown below.

android_fragment1_fragment2

Two things remain for our design goal to be complete.Fragmet2 displaying which button was clicked ,and taking us back to Fragment1 when its back button is clicked.We take care of displaying the clicked button first.

Like activities ,fragments have the onCreate( ) method.Inside this method ,android gives you a chance to do some set up before the fragment is displayed.In Fragment2 ,we implement this method and inside ,take the chance to retrieve the argument that MainActivity passed when it asked for Fragment2 to replace Fragment1 in in the activity layouts placeholder.The details are shown in the code snippet below.

Fragment2.java

package com.blikoon.fragmentstute;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

public class Fragment2 extends Fragment {
    private String mMessage;
    TextView infoTextView;
    Button backButton;

    public void onCreate( Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
       mMessage =getArguments().getString("fragment1_message");
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstancestate)
    {
        View v = inflater.inflate(R.layout.fragment2,container,
                false);
        infoTextView = (TextView)v.findViewById(R.id.info_text_view);
                infoTextView.setText(mMessage);
      

        backButton = (Button)v.findViewById(R.id.back_button);

        return v;
    }
}

Inside onCreate,we get the passed argument:

mMessage =getArguments().getString("fragment1_message");

and when the fragment is displayed in onCreateView,we get a reference to the textView an d pass in the information :which button was clicked.Run the app ,when you click a button of choice fragment2 is shown with which button was clicked in the textView as shown below.

android_fragment_f2_button

For the back button to take us to Fragment1 ,we attach a click listener to the backButton reference and inside ,use fragment transactions to replace Fragment2 with Fragment1.The details are shown below.

package com.blikoon.fragmentstute;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

public class Fragment2 extends Fragment {
    private String mMessage;
    TextView infoTextView;
    Button backButton;

    public void onCreate( Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
       mMessage =getArguments().getString("fragment1_message");
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstancestate)
    {
        View v = inflater.inflate(R.layout.fragment2,container,
                false);
        infoTextView = (TextView)v.findViewById(R.id.info_text_view);
        infoTextView.setText(mMessage);

        backButton = (Button)v.findViewById(R.id.back_button);
        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Fragment1 fragment1 = new Fragment1();
                FragmentTransaction transaction =
                      getActivity(). getSupportFragmentManager().beginTransaction();

                transaction
                        .replace(R.id.fragment_container, fragment1);
                transaction.commit();

            }
        });

        return v;
    }
}

The only thing you haven’t seen so far is that to call getSupportFragmentManager() from a fragment ,you have to pass by getActivity().Fragment().getActivity() gives you a reference to the host activity.

FragmentTransaction transaction =
      getActivity(). getSupportFragmentManager().beginTransaction();

If you run your app and hit the back button from fragment2 ,you can see that you are successfully turned back to Fragment1 .This is great our app is working as expected.We could also have implemented the back button feature by using interfaces the same way we did for Fragment1.I leave that to you as an exercise if interested.

Woow!This is one really long post.I covered as much as I could on Fragments and went as far as possible in the details to show how you can them to build your android applications.If you need to dig more on fragments ,I recomend the android documentation and codepath title on Creating and using fragments.The complete source code for the finalized project of this tutorial can be found on my git repository.I hope this has been informative to you and I would like to thank you for reading.

Posted in android, Tutorials and tagged , , , , .

Daniel Gakwaya loves computer Hardware/Software.He is a Software Engineer at BLIKOON and lead developer of bliboard-The whiteboard system currently marketed by the company.He is known to hack around on any piece of tech that happens to pick his interest. More on his tech endeavors here
Follow him on Twitter

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.