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 :
- Android FragmentStatePagerAdapter
- Android FragmentPagerAdapter
- 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.
Born in New Delhi, India. A software engineer by profession, an android enthusiast and an evangelist. My motive here is to create a group of skilled developers, who can develop something new and good. Reason being programming is my passion, and also it feels good to make a device do something you want. In a very short span of time professionally I have worked with many tech firms. As of now too, I am employed as a senior engineer in a leading tech company. In total I may have worked on more than 20 projects professionally, and whenever I get spare time I share my thoughts here at Truiton.
Thanks for the tutorial mate. Very helpful!
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.
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);
}
Do you have any code sample? Im in the same situation.
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
Many many thanks for such an useful article. Helped a lot… 🙂
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..
Nice.
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
Very helpfull post.
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.
tankyou
Thanks a ton!!!!!!!
It worked flawlessly for me.
Can you extend this tutorial till adding a PageTabStrip…. please!!!!
You can read this tutorial:
https://www.truiton.com/2015/06/android-tabs-example-fragments-viewpager/
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.
Nice Tutorial its helps me loat
Hello,
Nice tutorial.. My question is, if i open fragment within fragment , then how i can?
Thankz
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.
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.