Android Adventures - ViewPager
Written by Mike James   
Thursday, 20 November 2014
Article Index
Android Adventures - ViewPager
How FragmentPagerAdapter Works

FragmentPagerAdapter

All the FragmentPagerAdapter has to do is return the Fragment corresponding to the page number when asked for it and to say how many pages in total there are.

This means we only have to override two methods:

Fragment getItem(int pos)

and

int getCount()

First we need to add a class to the project.

Use New, JavaClass to add a class called myFragAdapter. Change its declaration so that it inherits from FragmentPagerAdapter. 

public class myFragAdapter
              extends FragmentPagerAdapter{

Now all we have to do is write the two methods. You can use the right click generate code,override methods to put stubs of each method into the class. 

The getCount is easy as we will just work with 3 pages for an example. 

public int getCount() {
 return 3;
}

 

The getItem method is only slighly more difficult:

public Fragment getItem(int i) {
 switch(i) {
  case 0: return Page.newInstance("One","");
  case 1: return Page.newInstance("Two","");
  default: return Page.newInstance("Three","");
 }
}

Notice that we create a new Fragment every time a page is requested. In some accounts of how FragmentPagerAdapter works you will find discussions of how and when Fragments should be created to make the whole think efficient. As it turns out getItem should always create a new Fragment when ever it is asked for a particular page. The reasons for this will be come apparent later.

Finally we need to add a default constructor and you can use the generate code, constructor command to auto-generate:

public myFragAdapter(FragmentManager fm) {
 super(fm);
}

 

We almost have a finished program but we have one small addition to make to the Activity. 

We have to assign the FragmentPagerAdapter to the PageViewer:

myVP.setAdapter(new myFragAdapter(
               getSupportFragmentManager()));

The complete onCreate method is now:

protected void onCreate(
              Bundle savedInstanceState){
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 ViewPager myVP=new ViewPager(this);
 myVP.setId(View.generateViewId());
 LinearLayout linL =
    (LinearLayout) findViewById(R.id.container);
 linL.addView(myVP);
 myVP.setAdapter(new myFragAdapter(
           getSupportFragmentManager()));
}

 

Now if you run the app you will see three pages complete with page numbers and you will be able to swipe from one to another. Notice that you cannot swipe earlier than page one or after page three this is what the limit that getCount sets.

How FragmentPagerAdapter Works

To get the best out of our use of ViewPager it is vital that you understand how it works. The basic ViewPager and PagerAdapter don't do any management of the Views that they are working with but the FragmentPagerAdapters do perform management.

What happens when you use a FragmentPagerAdapter is that the ViewPager uses it to initially get just two pages - page one and two and it displays page one. When the user swips to see page two the ViewPager asks the FragmentPagerAdapter for page three. It always has the next page ready to display.

When a page is more than one swipe away the ViewPager calls the FragmentPagerAdapter's destroyItem method to get rid of the page Fragment. 

So in theory the ViewPager has at most three active pages - the one you are looking at, the one to the left and the one to the right. 

In this way it can scroll to the next page very quickly. 

In the case of the FragmentPagerAdapter things are arranged to make life easy for you. 

When the page Fragment is created by getItem it is automatically added to the FragmentManager. If you recall all Fragments that are in the FragmentManager are persisted - that is the system will not destroy them. 

When a page Fragment needs to be destroyed the FragmentPagerAdapter simply uses the detach method of the FragmentManager which leaves it in the FragmentManager but deactivated. 

When a page that has been detached is needed again the FragmentPagerAdapter first checks to see if it is in the FragmentManager. If it is then it doesn't bother your getItem method it simply attaches the Fragment and it is ready for the ViewPager to display.

This method of working has some implications. 

The first is that your getItem method can create the page Fragments without checking to see if they already exist because it is only called when they don't already exist. In other words getItem is really firstGetItem. 

The second is that every page Fragment your getItem creates remains in the FragmentManager as long as the ViewPager is in use. 

The ViewPager might save some memory by deleting the View object that the page Fragment created but it is easy enough for the ViewPager to ask for the View to be created again by calling the Fragment's onCreateView method.

So this is all very simple, but it is only efficient if you are working with a small number of page Fragments. 

Suppose you have five page Fragments then after the user has looked each of them there will be five Fragments in the FragmentManger - all using memory because even though only three of them are required the rest are not destroyed.

This is fine for five fragments but what if you have 100 or more!?

You could very rapidly run out of memory. 

The solution to this is to use the second Fragment based PagerAdapter - FragmentStatePagerAdapter.

This works exactly like the FragmentPagerAdapter but with the big important difference that when the destroyItem method is called it really does remove the page Fragment from the FragmentManager and this means it is destroyed. 

Thus the FragmentStatePagerAdapter only keeps three Fragments in the FragmentManager at any time - the one the user is looking at and the two to either side ready to be swiped into view. 

When one of the destroyed page Fragments is needed. the FragmentStatePagerAdapter calls your getItem method with the page number specified. Your getItem method should simply generate a new instance of the Fragment. The FragmentStatePagerAdapter restores the state of the page as it was before it was destroyed. This automatically restores the state of the Fragment's View. If you want to preserve anything else you need to override onSaveInstanceState and onViewStateRestored and save anything you need in the Bundle.

To summarize:

  • It is perfectly OK for your getItem to generate a Fragment for a page each time it is requested. The getItem is only ever called when the Fragment needs to be instantiated.

  • The ViewPager typically only keeps three Fragments active - corresponding to the current page being viewed and two to either side.

  • If you use FragmentPagerAdapter all of the Fragments created by getItem are kept in memory. The three active Fragments are attached and the rest are in the FragmentManager but detached. Your getItem method is called just once for each page needed. 

  • If you use FragmentStatePagerAdapter only the three active Fragments are kept in the FragmentManager - any others are destroyed but their state Bundles are kept. Your getItem method is called when a destroyed item is needed and it should simply return a new instance of the Fragment. The FragmentStatePagerAdapter restores the state of the page's View to the new instance automatically. 

  • If you use FragmentStatePagerAdapter then you might need to store additional state manually and restore it manually.

  • FragmentPagerAdapter is simple and fast but can use a lot of resources. Use it when the number of pages is fixed and small.

FragmentStatePagerAdapter is potentially more complex, slower but it only ever keeps three Fragments in memory. Use it when the number of pages is variable and/or large. 

A Multipage Example

As an example of using FragmentStatePagerAdapter we can modify the getItem method to return any of 50 possible pages. 

First change the getCount method to return 50:

public int getCount() {
 return 50;
}

Instead of the switch statement which is often the way that a small number of pages are generated we can simply customize an instance of the Fragment:

public Fragment getItem(int i) {
 Page page=Page.newInstance(
                 Integer.toString(i),"");
 return page;
}

 

To check that the state of the View is automatically restored add an editText control and try typing in some new data on some of the pages. The only other change we need is to the declaration of the class:

public class myFragAdapter
           extends FragmentStatePagerAdapter{

 

Now when you run the program you should be able to work with 50 pages, all correctly numbered. Only three are kept in memory at any given time and any data that you type into the editText control should be preserved even if you swipe away to a far distant page and then return to it.

Androidgears

Where Next?

If you understand Fragments you should now be happy to create arbitrarily complex pages and interact with the user in any way you care to. 

Other things you can do to customize ViewPager include:

If you want to optimize the performance of the ViewPager in use with FragmentStatePagerAdapter than you can use the setOffscreenPageLimit to set the number of pages keep active.

There is a margin area between the pages that can be used to customize the scroll. Use the setPageMargin method to set the size of the margin in pixels. Use the setPageMarginDrawable to set an image that will be displayed in the page margin.

You can also customize the animation used to swipe between pages using the setPageTransformer method. if you understand Android property animations then how this works is obvious. 

 

You can download the code for the program from the CodeBin (note you have to register first).

 

Android Adventures - Mastering Fragments & Dialogs

coverfrag

Contents

This book is currently being revised. Chapter 5 and later refer to an earlier version of Android Studio - revisit for updates.

  1. Introducing Fragments
  2. Fragments and Android Studio XML
  3. Static Fragments
  4. Dynamic Fragments (Coming soon)

  5. Fragment And Activity Working Together
  6. Managing Fragments
  7. Custom dialogs using DialogFragment
  8. Dialog Classes In DialogFragment
  9. A NumberPicker DialogFragment Project
  10. ViewPager

If you are interested in creating custom template also see:

Custom Projects In Android Studio

Androidgears

 

 

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter,FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.

 

raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info



Last Updated ( Saturday, 25 July 2015 )