4.7 Android Fragments

Fragment was introduced in Android 3.0 (Honeycomb). Devices with lower configurations can make use of fragments. They are available as a part of support library. There is a difference in coding strategy when you use a support library and when you don’t. Primary difference is the use of FragmentActivity while we are using support library and use of Fragment when we are not using support library.

4.7.1 Introduction to Android Fragments

Android  fragment represents a part or behavior of user interface of activity. Multiple fragments can be brought together in a single activity. We shall create an example which will have more than one fragment in an activity. Once a fragment is created it can be reused multiple times. A fragment has its own life cycle. It has its own input and corresponding output.

It is recommended to embed the fragment life cycle in the activity as fragments’ life cycle movement is directly proportional to the master activity’s life cycle. When master activity pauses, the constituent fragments are also paused at the same time. When activity is destroyed, constituent fragments are also destroyed.   

Primary advantage of using fragments in Android is that we can create very flexible and dynamic User Interface which can be adapted gracefully by devices of different screen resolutions. So fragment can be thought of as salt which can be added to any dish of your choice which in turn increases the taste. Salt works impartially in all the dishes without any discrimination. Similarly fragment doesn’t differentiate activities. They are independent modules and are impartial to all the activities with which they are associated. Dividing activities or their corresponding layouts into fragments is not mandatory but increases flexibility of use. And as a developer it is very important to get user satisfaction. Even if you don’t want any user interface for the fragment, it is possible. Fragment can carry out background work without any user interface.  

Fragment resides in a ViewGroup inside an activity’s view hierarchy. It has its own layout which is managed by itself. Fragment is inserted in the layout by adding the <fragment/> tag. Let us study the life cycle of fragment. In case of sharing events with an activity, it is better to create a callback interface in fragment. This is defined in fragment but implementation should be done in the corresponding activity.

4.7.2 Lifecycle of Android fragment

Just like activities, fragments have callback methods which in turn conquer the lifecycle of fragments. They are as follows:

  • onAttach(): The activity is passed here. It is called when fragment is associated with the activity.
  • onCreate(): This method is called by the system when fragment is created. If you want to retain any component of the fragment while it is paused or stopped and meant to be resumed later then these components are to be initialized in this callback. 
  • onCreateView(): It is called for the creation of view hierarchy associated with the fragment. When fragment draws its user interface for the first time, this method is called by the system. In this method we return a view to the activity which houses the fragment.
  • onActivityCreated(): When onCreate() of activity returns, this method is called.
  • onStart(): If you want any modification in any component of the user interface which should be modified after fragment becomes visible are applied here.
  • onResume(): User interface updates which were paused are to be resumed here. Any thread or essential processes are to be resumed in this callback which was paused by the fragment. 
  • onPause(): When user leaves the fragment for the first time, system calls this method. The changes which are meant for persistence are to be committed here.
  • onStop(): Leftover UI updates, threads or processes which are not essential when fragment is not visible are suspended here.
  • onDestroyView(): When the view hierarchy of fragment is going to be removed, this method is called.
  • onDestroy(): All the resources are cleaned in this stage.
  • onDetach(): This is called when fragment gets detached from the activity. This is the final callback method related to the fragment.

Figure Lifecycle of Android fragment

                                                         Figure  - Lifecycle of Android fragment

4.7.3 Android Fragment States

A fragment can exist in three states and they are as follows:

  1. Resumed: In this state, activity is running and fragment is visible.
  2. Paused:  In this state another activity has focus and it is running in foreground. It may be transparent or it has acquired the device’s screen partially. In this case, activity containing fragment is still alive and fragment is still visible.
  3. Stopped: A stopped fragment is still alive but it will not be visible to the user. It will get killed if the master activity dies. The reason behind this stoppage might be the removal of fragment or the parent activity would have been stopped. 

4.7.4 Android Fragment Example

Open your IDE and create a project. Name it as you like. I am naming it as FragmentExample app. Please be patient while you code and go in the exact sequence. We shall have two fragments bind in one activity. In first fragment we shall enter data and in other fragment this data will be displayed.  You can link any xml file to the corresponding classes. But for a safer execution, I shall recommend you to do exactly as I do. Let us start. Open your activity_main.xml file and delete everything there and add code it as shown in the following listing:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello Readers!!" />
    <LinearLayout
        android:id="@+id/first"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="NAME"
            android:textAppearance="?android:attr/textAppearanceSmall" />
        <EditText
            android:id="@+id/editTextName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:ems="10"
            android:hint="Name"
            android:inputType="textPersonName" >
            <requestFocus />
        </EditText>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/second"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Email"
            android:textAppearance="?android:attr/textAppearanceSmall" />
        <EditText
            android:id="@+id/editTextEmail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="email id"
            android:inputType="textEmailAddress" />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/third"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="horizontal" >
        <Button
            android:id="@+id/button1"
            style="?android:attr/buttonStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Show Name" />
        <Button
            android:id="@+id/buttonEmail"
            style="?android:attr/buttonStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Show email" />  
  </LinearLayout>
</LinearLayout>

                                           Figure -  activity­_main.xml file of first Android Fragment  

The graphical layout should be similar to the following snapshot: 

Graphical layout of First Android fragment

                                                        Figure - Graphical layout of First  Android fragment

Create another xml file and name it as second.xml. This is the xml file of our second fragment. Code it as shown in the following listing

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <TextView
        android:id="@+id/textViewNamePerson"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Name of person"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    <TextView
        android:id="@+id/textViewEmailSecond"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textViewNamePerson"
        android:layout_below="@+id/textViewNamePerson"
        android:layout_marginTop="27dp"
        android:text="Email ID"
        android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>

                                         Figure - xml file of second  Android Fragment  

Graphical layout of second fragment should be similar to the following snapshot:

Graphical layout of second Android fragment

Figure - Graphical layout of second Android fragment

Now we shall design the xml file of our app. In this xml file we shall include the two fragments. Create an xml file and name it as first.xml. Code it as shown in the following listing:

Now we shall design the xml file of our app. In this xml file we shall include the two fragments. Create an xml file and name it as first.xml. Code it as shown in the following listing:

<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" >
    <fragment
        android:id="@+id/FragmentFirst"
        android:name="com.android.tution.Fragments.FragmentFirst"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        tools:layout="@layout/activity_main" />
    <fragment
        android:id="@+id/FragmentSecond"
        android:name="com.android.tution.Fragments.FragmentSecond"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        tools:layout="@layout/second" />
</RelativeLayout>

                                        Figure - first.xml file

As soon as you save this file, both the fragments will appear together in graphical layout. Graphical layout should be similar to the following snapshot:

Graphical layout of Android Fragment app

Figure - Graphical layout of Android Fragment app

Now let us code the corresponding classes. Create a class and name it as FragmentFirst.java and code it as shown in the following listing:

package com.android.tution.Fragments;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Fragment;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class FragmentFirst extends Fragment {
    private static EditText edit, edited;
    private static int Position = 10;
    private static int pos = 11;
    FirstListener activityCallback;
    public interface FirstListener {
        public void onButtonClick(int position, String text);
        public void ButtonClick(String string);
    }
    @Override
    public void onAttach(Activity activity) {
        // TODO Auto-generated method stub
        super.onAttach(activity);
        try {
            activityCallback = (FirstListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + "must implement FirstListener");
        }
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        // return super.onCreateView(inflater, container, savedInstanceState);
        View view = inflater.inflate(R.layout.activity_main, container, false);
        edit = (EditText) view.findViewById(R.id.editTextName);
        edited = (EditText) view.findViewById(R.id.editTextEmail);
        final Button button = (Button) view.findViewById(R.id.button1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                buttonClicked(v);
            }
        });
        final Button b = (Button) view.findViewById(R.id.buttonEmail);
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View vi) {
                // TODO Auto-generated method stub
                clickButton(vi);
            }
        });
        return view;
    }
    protected void clickButton(View vi) {
        // TODO Auto-generated method stub
        activityCallback.ButtonClick(edited.getText().toString());
    }
    protected void buttonClicked(View v) {
        // TODO Auto-generated method stub
        activityCallback.onButtonClick(Position, edit.getText().toString());
        }
}

                                                                         Figure -  First fragment

Let us go for the second fragment and for this we have to create a new class. Name it FragmentSecond.java and code it as shown in the following listing:

package com.android.tution.Fragments;
import android.annotation.TargetApi;
import android.app.Fragment;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class FragmentSecond extends Fragment {
    private static TextView texted, texts;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        // return super.onCreateView(inflater, container, savedInstanceState);
        View v = inflater.inflate(R.layout.second, container, false);
        texted = (TextView) v.findViewById(R.id.textViewNamePerson);
        texts = (TextView) v.findViewById(R.id.textViewEmailSecond);
        return v;
    }
    public void changeTextProperties(int fontSize, String text) {
        texted.setTextSize(fontSize);
        texted.setText(text);
        // texts.setTextSize(fontSize);
        // texts.setText(text);
    }
    public void setEmail(String email) {
        texts.setText(email);
    }
}

                                                  Figure - Second fragment

Finally let us code our main activity file. Open the file saying MainActivity.java and code it as shown in the following listing:

package com.android.tution.Fragments;
import android.app.Activity;
import android.app.FragmentManager;
import android.os.Bundle;
public class MainActivity extends Activity implements
        FragmentFirst.FirstListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first);
    }
    public void onButtonClick(int fontSize, String text) {
        // TODO Auto-generated method stub
        FragmentManager fm = getFragmentManager();
        FragmentSecond fSecond = (FragmentSecond) fm
                .findFragmentById(R.id.FragmentSecond);
        fSecond.changeTextProperties(fontSize, text);
    }
    @Override
    public void ButtonClick(String tech) {
        // TODO Auto-generated method stub
        FragmentManager fmanager = getFragmentManager();
        FragmentSecond fsec = (FragmentSecond) fmanager
                .findFragmentById(R.id.FragmentSecond);
        fsec.setEmail(tech);
    }
}

                                          Figure- Main activity file of Android Fragment App

Our last task is to check the manifest file. So open it and cross check it with following lines of code:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.tution.Fragments"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="18" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.android.tution.Fragments.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

                                                          Figure - manifest file of Android Fragment application

We are done with implementation part. Now create a suitable emulator and run application. First run should produce a similar output as shown in the  following snapshot:

Homepage of Android Fragment app

Figure  - Homepage of Android Fragment app

Now enter any name in the area indicated to enter a name. For instance I am entering android in this space and press the button saying Show Name. Emulator should look similar to the following snapshot:

Name entered in one fragment is displayed in second fragment

Figure - Name entered in one fragment is displayed in second fragment

Purposely, I want to clear any doubt about the validity of app. So enter any e-mail id in the space provided for entering e-mail. Please check that second fragment is same. There is no change in second fragment until button saying Show E-mail is pressed. Emulator should be similar to the following snapshot:

Emulator after entering a demo e-mail id

Figure - Emulator after entering a demo e-mail id

Now press the button saying Show email and as a result second fragment should change and it should display the e-mail id entered in the first fragment. Output should be similar to the following snapshot:

Final Output of Android Fragments example

Figure - Final Output of Android Fragments example

Congratulations buddies!!! Hope you enjoyed this cute and complete example of fragment. See you in the next section. Till then keep practicing. Happy App Developing!!