5

I want to know more about ViewPager behavior. I have a FragmenPagerAdapter :

public class DatePagerAdapter extends FragmentPagerAdapter {

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


        @Override
        public Fragment getItem(int position) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            int offset = position - 100;
            calendar.add(Calendar.MONTH, offset);
//            Toast.makeText(TestActivity.this,(calendar.get(Calendar.MONTH)+1)
            Log.v("CALENDAR", "" + position);
            TestFragmentDate date = TestFragmentDate.newInstance(TestActivity.this, calendar);
            return date;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            return super.instantiateItem(container, position);
        }
    }

And the code in my Activity :

adapter = new DatePagerAdapter(getSupportFragmentManager());
        MinFragmentPagerAdapter wrapperMin = new MinFragmentPagerAdapter(getSupportFragmentManager());
        wrapperMin.setAdapter(adapter);
        PagerAdapter wrapper = new InfinitePagerAdapter(wrapperMin);
        viewPager = (ViewPager) this.findViewById(R.id.pager);
        viewPager.setAdapter(adapter);
        viewPager.setCurrentItem(100);
        viewPager.addOnPageChangeListener(this);

According to my senior, ViewPager always draw 3 fragments, and keep reuse them. For example, at first I have view at position : 99, 100, 101 If I roll right, it will destroy 99 and create 102, and so on. But, when I debug at the function getItem, at first it did run into this function, but when I roll right for 5 or 6 page, and then roll back, it didn't run into getItem, at the position which is supposed to be destroyed.

So would anyone please explain for me about ViewPager's behavior ? Thank you.

soshial
  • 5,906
  • 6
  • 32
  • 40
Nguyen Quang Anh
  • 315
  • 1
  • 3
  • 12
  • try with this http://stackoverflow.com/questions/33706456/fragmentstatepageradapter-handling-getitem-position/33864983#33864983 – Parag Chauhan Dec 02 '15 at 10:09

2 Answers2

16

Google's guide says:

FragmentPagerAdapter

This version of the pager is best for use when there are a handful of typically more static fragments to be paged through, such as a set of tabs. The fragment of each page the user visits will be kept in memory, though its view hierarchy may be destroyed when not visible. This can result in using a significant amount of memory since fragment instances can hold on to an arbitrary amount of state. For larger sets of pages, consider FragmentStatePagerAdapter.

And about FragmentStatePagerAdapter:

This version of the pager is more useful when there are a large number of pages, working more like a list view. When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.

Conclusion : Use FragmentStatePageAdapter in your case, that is you don't want Fragment attached to your ViewPager to be destroyed.

You can also use viewpager.setOffscreenPageLimit(<no of fragments>); to limit How many pages will be kept offscreen in an idle state.

Vipul Asri
  • 8,903
  • 3
  • 46
  • 71
  • Ok I just read on Google's guide. It said that the default value of `setOffscreenPageLimit` is 1. So if I don't set some certain `limit`, it would be 2 pages that were keep, the visible page, and 1 offscreen page. But then in the code that I posted, at first run it create 3 pages, 1 visible, 1 to the left and 1 to the right. This made me confused... Would you explain this behavior for me ? Thanks – Nguyen Quang Anh Dec 02 '15 at 12:43
  • No, setting `setOffscreenPageLimit` to 1(default). Only one page will retained in memory that can be present on either side of the current page. If you have 3 pages/fragments and want all of them to be retained you have to `setOffscreenPageLimit` to 2. – Vipul Asri Dec 02 '15 at 12:58
  • I swear that it was 1 (on default). And when I debug, it really jump into the `getItem` 3 times, and the positions are 99, 100, 101. The middle one is 100 – Nguyen Quang Anh Dec 02 '15 at 13:01
  • I didn't said `setOffscreenPageLimit` default value isn't 1 and please be clear regarding your question – Vipul Asri Dec 02 '15 at 13:03
  • Ok, let me make my question clear. I just want to know why ViewPager and its Adapter behave the way I didn't expected. `setOffScreenPageLimit` is 1 (by default). So I would say that the first time it run, it will create 2 pages, 1 visible, and 1 offscreen. It means that it will run `getItem` in its adapter 2 times. That is the behavior I was expected. However, it run `getItem` 3 times, 1 for the visible page, 1 to the left and 1 to the right. So I was asking why it behave like this. – Nguyen Quang Anh Dec 02 '15 at 13:07
  • @VipulAsri I am using `ViewPager2` and `FragmentStateAdapter` with `setOffscreenPageLimit(1);`. Which `Fragment` class method will get called when unloaded fragments are destroyed ? – Rajat Sangrame Feb 28 '20 at 09:02
0

As said before:

You can also use viewpager.setOffscreenPageLimit(<no of fragments>); to limit How many pages will be kept offscreen in an idle state.

From the official documentation:

setOffsetPageLimit(): Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.

It means setOffScreenPageLimit(1) will keep 1 page to the left and/or 1 page to the right depending on what position of the viewPager you are.