Home » Android » Basics of Android Fragment

Basics of Android Fragment

Welcome to the first module of Android Fragment tutorial. In this module we will learn about basics of android fragment, advantage of android fragments, android fragment lifecycle. And at last we see how to create simple android fragment and where can we use them.

Below are the topics that we will cover in this module:

  • What are android fragments?
  • Advantages
  • Lifecycle
  • Where can we use android fragments?
  • Prerequisite
  • Example to create android Fragments

 

What are android fragments?

As we all know the android market is growing rapidly, there are 100′s of android devices with different screen sizes. It was getting very difficult for developers to create an application layout which will support all the different range of android phones, which will support orientation and which will support smooth rendering of UI on varying screen sizes. Another major issue that developers faced was to create an app which supports both; android smartphones as well as android tablets (as tablets marketing is growing very rapidly). These things are the key foundation concept for Fragments. So android Fragments is the answer for all the above mentioned problems that developers faced previously while developing an android app.
Let’s take a look how it works to get a better understanding.

 

fragment_1st_portrait

Fig 1.1

fragment_1st_landscape

Fig 1.2

 

We have an application which has 2 screens; first screen displays the list of items and clicking on an item will navigate the user to another screen which is item detail screen.
In Fig 1.1 application is running in portrait mode; there are two different screens, one is for list and another is for detail.
In Fig 1.2 application is running in landscape mode; so instead of displaying two different screens, we are trying to utilize the available screen space and display the list at left and details of selected list item at right of the screen.

The above behavior can be achieved by using android fragments. Android fragment allows to utilize the given screen space appropriately.

Advantage
The main advantage of fragments is the reusable views, as we saw in above example that the same application is rendering properly in portrait mode as well as in landscape mode. One more advantage is, Fragments have backstack support, that means keeping track of view’s history, you will learn about fragment backstack in next module.

Fragment Lifecylce

fragment_lifecycle

                   Fragment Lifecycle

 

onAttach() method is called when the fragment is associated with its activity.
onCreate() method is the initial call to create the fragment.
onCreateView() method create and return the associated fragment view.
onActivityCreated() method is called when associated activity completes its own onCreate().
onStart() method is called when fragment is visible to the user.
onResume() method is called when fragment is active to the user.
onPause() method is called when fragment is visible but user cannot interact with the fragment. i.e. fragment is visible but not active.
onStop() method is called when fragment is no longer visible to the user
onDestroyView() method cleanup the associated view’s resources
onDestroy() method does final cleanup of fragment from stack.
onDetach() method is called when fragment is detached from its associated activity

The important is, activity’s callback of same name is always gets called before the fragment’s callback method, that means activity’s onResume() will gets called first then fragments onResume()

Where can we use android fragments?


– Fragments can be used to achieve tabbed view
– Fragments can be used to display list maps and dialogs
– Fragments can be used to display customizable actionBar

This is all about theoretical stuff about android fragments, now let’s move ahead to get some practical learning.

Prerequisite
To start with android fragments you should have basic knowledge of java and android Application development

Example to create android Fragments
It’s time to get your hands dirty with some coding stuff. Let’s take a look how we can create fragments in android.

There are few basic steps to create fragments in android:

1. Create an activity which will hold all the fragments.
2. Create two classes which will extend Fragment class.
3. Create xml for the newly created classes.
4. Inflate the layout from xml in onCreateView() method of both the classes.
5. In activity xml add the <fragment> and set the class, for example <fragment class: “com.codeureka.fragmentsexample.SpeakerListFragment” … />
6. To make it responsive create another xml in layout-land folder which will be called in landscape mode.

Let’s check out each step in more detail.

1. Create an activity which will hold all the fragments.

SpeakerListActivity.java

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

public class SpeakerListActivity extends Activity implements SpeakerFragmentInterface {

@Override
protected void onCreate(Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   super.onCreate(savedInstanceState);
   setContentView(R.layout.speaker_list_activity);
 }
@Override
public void onSpeakerSelected(int index) {
   // TODO Auto-generated method stub
 }
}

SpeakerFragmentInterface.java

public interface SpeakerFragmentInterface {
   void onSpeakerSelected(int index);
}

I have a class called SpeakerListActivity.java which extends Activity class and implements SpeakerFragmentInterface.

SpeakerFragmentinterface interface has onSpeakerSelected() method which is used to implement the logic to display selected speaker details.

 

2. Create two classes which will extend Fragment class

SpeakerListFragment.java

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class SpeakerListFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   return null;
  }
}

SpeakerDetail.java

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 SpeakerDetail extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
   // TODO Auto-generated method stub 
   return null;
  }
}

In Above step I have created two classes, SpeakerListFragment.java which will display the list of speakers and SpeakerDetail.java which will display selected speaker details.

 

3. Create xml for the newly created classes.

Speaker_list.xml – to display list of speakers

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

<ListView
android:id="@+id/speakerList"
android:layout_height="wrap_content"
android:layout_width="match_parent">
</ListView>

</LinearLayout>

Above xml is pretty straight forward, it has one listview widget to display the speaker list.

Speaker_detail.xml – to display the details of selected list item

<?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/txtView_speakerDetails"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

Above xml have one textView widget which will display the data of selected list item.

So far we have created two different classes and two different xml files for two different fragments.

 

4. Inflate the layout from xml in onCreateView() method of both the classes

In this step we will associate the xml files with their corresponding fragments and will inflate the data. So let’s modify both the classes we created previously.

SpeakerListFragment.java

public class SpeakerListFragment extends Fragment {
  ListView listView;
  String[] speakerList = new String[] { "Himanshu Chahar", "Piyush Chahar" };

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
   View view = inflater.inflate(R.layout.speakers_list, container, false);
   listView = (ListView) view.findViewById(R.id.speakerList);
   ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1,
speakerList);
   listView.setAdapter(adapter);
   return view;
  }
}

In Above code I have String Array “speakerList” which is the list of all the speaker’s name. In onCreateView() I am using inflater() method to inflate the fragment view, then I have created an Arrayadapter which will create a simple list item layout with one textview for each of the speakerList item.
The finally  we are passing that adapter to listview and finally returning the inflated view.

Now modify the other class.
SpeakerDetail.java

public class SpeakerDetail extends Fragment {

  TextView textView;
  String[] speakerDetails = new String[] {
"Himanshu's Session is on Sunday, 23rd March, about Mobile application development.",
"Piyush's Session is on Friday, 21st March, about Marketing strategies." };

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   View view = inflater.inflate(R.layout.speaker_detail, container, false);
   textView = (TextView) view.findViewById(R.id.txtView_speakerDetails);
   return view;
  }
}

In this class I have created string array speakerDetails which will display the details of selected speaker.

 

5. In activiy xml add the <fragment> and set the class for example <fragment class: “com.codeureka.fragmentsexample.SpeakerListFragment” … />

speaker_list_activity.xml

<?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/speakersFragment"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
class="com.codeureka.fragmentsexample.SpeakerListFragment" >
</fragment>

</LinearLayout>

This is the xml file which is passed in setContentView() of SpeakerListActivity.java, which means only SpeakerListFragment will be rendered on creation of SpeakerListActivity.java

 

6. To make it responsive create another xml in layout-land folder which will be called in landscape mode.

Create another xml file with the same name which will be rendered when device is in landscape mode.

speaker_list_activity.xml

<?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/speakersFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.codeureka.fragmentsexample.SpeakerListFragment" >
</fragment>

<fragment
android:id="@+id/speakerDetailFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.codeureka.fragmentsexample.SpeakerDetail" >
</fragment>

</LinearLayout>

Above xml will display both the fragments on the same screen.

So above we have discussed about the 6 major steps which are used to create the fragment but we have only completed 60%. Remaining 40% is the logic to handle the click event functionality.
There are 4 major steps involved to handle click event in fragments.

1. Create an interface, and create public method which will handle click event.
2. Implement that interface in SpeakerListActivity.java and add logic to display the speakerDetail fragment.
3. Call interface method on List item click and pass the clicked item index.
4. Use onSaveInstanceState method to save the index of clicked item.

So let’s go through each step one by one
1. Create an interface, and create public method which will handle click event.
We have already covered this step in previous section.

2. Implement that interface in SpeakerListActivity.java and add logic to display the speakerDetail fragment

 

@Override
public void onSpeakerSelected(int index) {
   // TODO Auto-generated method stub
   SpeakerDetail speakerDetailFragment = (SpeakerDetail) getFragmentManager().findFragmentById(R.id.speakerDetailFragment);
   if (speakerDetailFragment != null && speakerDetailFragment.isVisible()) {
     speakerDetailFragment.setDetails(index);
   }
   else{
     Intent intent = new Intent(this, SpeakerDetailActivity.class);
     intent.putExtra("speakerIndex", index);
     startActivity(intent);
   }
}

In this method I am getting a reference of SpeakerDetail fragment. Then I am checking if the speakerDetail is already visible, if yes, then call setDetails() method (this method is defined in step 4)and pass selected speaker’s index value and if it is not visible then create an intent and pass the index value.
getFragmentManager() returns the FragmentManager which can be used to interact with fragments associated with this activity.
3. Call interface method on List item click and pass the clicked item index.

So for this step we need to modify SpeakerListFragment.java and implement itemClickListener for listView

listView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
   // TODO Auto-generated method stub
   SpeakerFragmentInterface coordinator = (SpeakerFragmentInterface)getActivity();
      coordinator.onSpeakerSelected(arg2);
   }
});

4. Use onSaveInstanceState method to save the index of clicked item.
This is last step but not the least. To understand its importance of this step, lets consider one scenario, as we know whenever we change the orientation the onCreate() method gets called, now for example user has selected list item 2 and changes the orientation, the oncreate() method will get called and the application will display the details of first item which is not acceptable by any user. In that case it is very important to save the fragment state, this is another advantage of fragment over custom views.

So in SpeakerDetail.java we will have to override onSaveInstanceState() method and define setDetails() method which will set the details based on index value of selected item.

@Override
public void onSaveInstanceState(Bundle outState) {
   // TODO Auto-generated method stub
   outState.putInt(INDEX_KEY, index);
}

public void setDetails(int indexValue){
   index = indexValue;
   textView.setText(speakerDetails[index]);
}

Finally we have covered 100% to create our first basic fragment. It may look little complicated at first place but it is really simple if you keep these 10 steps in mind.

If you have run the above code, you must have noticed following things:
– when you start the activity in portrait mode only the list will be visible.
– when you click on list item in portrait mode, speaker detail screen will appear.
– when you are in landscape mode list and detail screen will be displayed side by side.
– when you click on list item in landscape mode, speaker details will be displayed on same screen (on right side).

Now lets consider one more scenerio(don’t get affraid, its always better to consider more scenerios), in above example there are very few list items and if we are running the above code on tablet (in portrait mode), almost more than half of the height will be wasted (which is not a good behaviour at all). So in that case, what we can do is divide the screen in two parts and display list in first half and details in second half.

 

To achieve that behavior we just have to modify little bit of code.

SimpleFragmentActivity.java

public class SimpleFragmentActivity extends Activity implements SpeakerFragmentInterface {
@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.simple_fragment_activity);
}

@Override
public void onSpeakerSelected(int index) {
   SpeakerDetail speakerDetailFragment = (SpeakerDetail) getFragmentManager().findFragmentById(R.id.speakerDetailFragment);
   if (speakerDetailFragment != null && speakerDetailFragment.isInLayout()) {
      speakerDetailFragment.setDetails(index);
   } 
  }
}

simple_fragment_activity.xml – under layout 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/speakersFragment"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
class="com.codeureka.fragmentsexample.SpeakerListFragment" >
</fragment>

<fragment
android:id="@+id/speakerDetailFragment"
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1"
class="com.codeureka.fragmentsexample.SpeakerDetail" >
</fragment>

</LinearLayout>

simple_fragment_activity.xml – under 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/speakersFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.codeureka.fragmentsexample.SpeakerListFragment" >
</fragment>

<fragment
android:id="@+id/speakerDetailFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.codeureka.fragmentsexample.SpeakerDetail" >
</fragment>

</LinearLayout>

So above code changes will display the list in first half and details in second half. You must have noticed that there is no major change, the only change is in layout. Below is the screenshot of the result

fragment_same_screen_list

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>