Android FragmentPagerAdapter Example


Go By Streetcar Part III

How cool is it to have an app which has swipe views, it makes app interactive and fun to use, right? So being a mobile app consultant at Truiton I was working on an app where segmented forms were to be filled by user. I thought why not use swipe tabs and sliding views. I searched and found this can be implemented by Android ViewPager class, which is used in conjunction with Android FragmentPagerAdapter class or Android FragmentStatePagerAdapter class. Since any sort of software development requires precision and accuracy in work my purpose was solved by the later one. Still I decided to write a tutorial about Android FragmentPagerAdapter Example.

There are two ways to implement Android ViewPager class, but this tutorial only focuses on Android FragmentPagerAdapter with an example. Now since both adapters have different ways of working, you might want to read about the other one too, have a look at my series on PagerAdapters :

  1. Android FragmentStatePagerAdapter
  2. Android FragmentPagerAdapter
  3. Android FragmentPagerAdapter vs FragmentStatePagerAdapter

In my previous tutorial I mentioned a case, if we wish to keep the fragment in the memory. Here steps in Android FragmentPagerAdapter, the main advantage of using Android FragmentPagerAdapter is that, it keeps the fragment in memory. This definitely increases the memory usage, therefore it is advised to use Android FragmentPagerAdapter only when there are less number of fragments. If you app has non changing fragments like, fragments with images or static text it might work even better. But using Android FragmentPagerAdapter for large number of fragments would result choppy and laggy UX.

Android FragmentPagerAdapter Example

Lets start with the main activity, this activity is where the Android FragmentPagerAdapter class is declared. Have a look at MainActivity.java.

package com.truiton.fragmentpageradapter;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends FragmentActivity {
	static final int ITEMS = 10;
	MyAdapter mAdapter;
	ViewPager mPager;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fragment_pager);
		mAdapter = new MyAdapter(getSupportFragmentManager());
		mPager = (ViewPager) findViewById(R.id.pager);
		mPager.setAdapter(mAdapter);

		Button button = (Button) findViewById(R.id.first);
		button.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				mPager.setCurrentItem(0);
			}
		});
		button = (Button) findViewById(R.id.last);
		button.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				mPager.setCurrentItem(ITEMS - 1);
			}
		});
	}

	public static class MyAdapter extends FragmentPagerAdapter {
		public MyAdapter(FragmentManager fragmentManager) {
			super(fragmentManager);
		}

		@Override
		public int getCount() {
			return ITEMS;
		}

		@Override
		public Fragment getItem(int position) {
			switch (position) {
			case 0: // Fragment # 0 - This will show image
				return ImageFragment.init(position);
			case 1: // Fragment # 1 - This will show image
				return ImageFragment.init(position);
			default:// Fragment # 2-9 - Will show list
				return TruitonListFragment.init(position);
			}
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

In the above class one can see that MainActivity extends FragmentActivity and in this class, both MyAdapter and ViewPager class are instantiated. If you look closely you would find that MyAdapter class extends Android FragmentPagerAdapter class. Lets have a look at the extended Android FragmentPagerAdapter class, here exists a method by the name of getItem. This getItem method is the one which calls all the fragments which are to be displayed according to the position. MainActivity.java is displayed by layout fragment_pager.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:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="4dip" >

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1" >
    </android.support.v4.view.ViewPager>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0"
        android:gravity="center"
        android:measureWithLargestChild="true"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="First" >
        </Button>

        <Button
            android:id="@+id/last"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Last" >
        </Button>
    </LinearLayout>

</LinearLayout>

Above is the main layout where all fragments would be displayed. Have a look at android.support.v4.view.ViewPager tag, since this tag is used here, this app would run on android devices lower than API version 11 too. Next lets have a look at ImageFragment.java.

package com.truiton.fragmentpageradapter;

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

public class ImageFragment extends Fragment {
	int fragVal;

	static ImageFragment init(int val) {
		ImageFragment truitonFrag = new ImageFragment();
		// Supply val input as an argument.
		Bundle args = new Bundle();
		args.putInt("val", val);
		truitonFrag.setArguments(args);
		return truitonFrag;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		fragVal = getArguments() != null ? getArguments().getInt("val") : 1;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View layoutView = inflater.inflate(R.layout.fragment_image, container,
				false);
		View tv = layoutView.findViewById(R.id.text);
		((TextView) tv).setText("Truiton Fragment #" + fragVal);
		return layoutView;
	}
}

In the above class a static method by the name of init is declared. This init method is called in the extended Android FragmentPagerAdapter class with position of the fragment as argument. This argument is later on used in onCreate and onCreateView method of this ImageFragment. The layout file for this class is fragment_image.xml.

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

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal"
        android:text="@string/hello_world"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/text"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="36dp"
        android:src="@drawable/truiton" />

</RelativeLayout>

Now have a look at the second type of fragment used in Android FragmentPagerAdapter Example, TruitonListFragment.java.

package com.truiton.fragmentpageradapter;

import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class TruitonListFragment extends ListFragment {
	int fragNum;
	String arr[] = { "This is", "a Truiton", "Demo", "App", "For", "Showing",
			"FragmentPagerAdapter", "and ViewPager", "Implementation" };

	static TruitonListFragment init(int val) {
		TruitonListFragment truitonList = new TruitonListFragment();

		// Supply val input as an argument.
		Bundle args = new Bundle();
		args.putInt("val", val);
		truitonList.setArguments(args);

		return truitonList;
	}

	/**
	 * Retrieving this instance's number from its arguments.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		fragNum = getArguments() != null ? getArguments().getInt("val") : 1;
	}

	/**
	 * The Fragment's UI is a simple text view showing its instance number and
	 * an associated list.
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View layoutView = inflater.inflate(R.layout.fragment_pager_list,
				container, false);
		View tv = layoutView.findViewById(R.id.text);
		((TextView) tv).setText("Truiton Fragment #" + fragNum);
		return layoutView;
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		setListAdapter(new ArrayAdapter<String>(getActivity(),
				android.R.layout.simple_list_item_1, arr));
	}

	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		Log.i("Truiton FragmentList", "Item clicked: " + id);
	}
}

In the above class, the only difference is, that ListFragment is used, rest is same as in ImageFragment. It has a static init method which is called from extended Android FragmentPagerAdapter. It uses layout fragment_pager_list.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:background="@android:drawable/gallery_thumb"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal"
        android:text="@string/hello_world"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" >

        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:drawSelectorOnTop="false" />
    </FrameLayout>

</LinearLayout>

After defining all the classes and layouts your app should look like screenshots below

In this tutorial I defined a class which extended FragmentActivity, and instantiated extended version of Android FragmentPagerAdapter and ViewPager. This whole Android FragmentPagerAdapter example is made with support library, hence this would run on all android devices. Again to sum up, I would say that use Android FragmentPagerAdapter only when you have low amount of fragments that you want to keep in memory. Otherwise it will create a memory overhead and affect your app’s performance. This would work even better with non changing fragments. If you still have concerns on which PagerAdapter to use, have a look at Android FragmentPagerAdapter vs FragmentStatePagerAdapter. Hope this helped you out, if it did please like and share this with your friends on Google+ and Facebook. Also like our Facebook page for updates.

About Mohit Gupt

An android enthusiast, and an iPhone user with a keen interest in development of innovative applications.


Leave a comment

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

19 thoughts on “Android FragmentPagerAdapter Example

  • anuj

    Hi Mohit Sir! Thanks a lot for this tut…

    In above example suppose if we want to open 1st fragment from List-Fragment and also want to show which item was clicked… So what can we do in this case?
    Can you please help me? I am new to android developement.

    • Mohit Gupt Post author

      Hi Anuj,
      You can do this by adding a static method in MainActivity, which would be called from the ListFragment’s onListItemClick method:


      static void callFragment(int num){
      mPager.setCurrentItem(num);
      }

  • Matt Sellner

    Hi Mohit,

    Thanks for the tutorial!

    How would I go about changing the list data from the main activity? I can pass the initial array through the init (return TruitonListFragment.init(position,som_array);) but when the dataset changes in the MainActivity how do I notify the listfragment to update?

    Thanks!

    Matt

  • sandeep

    Nice tutorial.. great post
    Mohit, I have a tabhost which hosts two activities. How can i recreate the activity which is under tabhost. Please give me solution for this. Sorry for asking this here.Thanks in advance..

  • srinivas

    Hi Mohit,

    This is very helpfull for me.

    I am facing a problem with FragmentStatePagerAdapter, in my App i have 4 Fragments,If i left my App idle for some 20 minutes and above, Currently showing Fragment state is losing.i.e UI is lost, showing only empty screen..Can you please help me to solve this.

    Thanks,
    Sinivas

  • Naveen

    Nice tutorial.. great post,

    I want check a flag true or false on the basis of that I want make Pager swipe enable or disable.

    Please help me how to do that.

  • Ameya

    I’ve created a tablayout with Viewpager.The Tablayout has three 3 fragments ‘Photo’,’Video’,’Docs’. Each fragment has a gridview. In ‘Photo’ fragment images are loaded to the gridview as thumbnails, In ‘Video’ fragment videos are loaded to the gridview as thumbnails and so on. When an image is loaded to the Gridview in ‘Photo’ fragment and after that when the application is killed and opened again, the Gridview has lost its state that is it doesn’t have the uploaded images. I know this is happening because the onCreateView is creating the entire UI again. But how to save the State of the Fragment before it gets killed ?

    Can you please make an example demonstrating how to save the state of the fragments which have gridview !

    Thank you in advance.

  • Pedro

    Hey, I am implementing your solution for FragmentPagerAdapter (kind of), but with some modification.

    The main modification is that images are loaded into each “slide” by clicking the corresponding ImageView, up to 6 images

    My problem: everything works fine, images are loaded by clicking on the ImageView and displayed correctly, however, let’s say I click and load image #0, them move forward to image #3, now if I go back to image #0 it is gone….any clue or suggestion about it??.

    Thanks.

  • Hina Arora

    How can we maintain the previous fragment state?
    The problem I am facing is on back pressed from any fragment , it will lead to exit an app.