Home » Android » java – ViewPager.setOffscreenPageLimit(0) has no effect at all. How do I only load one page at a time in a ViewPager?

java – ViewPager.setOffscreenPageLimit(0) has no effect at all. How do I only load one page at a time in a ViewPager?

Posted by: admin June 15, 2020 Leave a comment

Questions:

even when I set oViewPager.setOffscreenPageLimit(0) my view pager still loads 1 off screen page on each side of the visible page.

How do I make it only load the page when the user slides to it?

My adapter if it helps:

public class MainPagerAdapter extends FragmentPagerAdapter {
    protected static final String[] CONTENT = new String[] { "page 1", "page 2", "page 3", "page 4", };

    private int mCount = CONTENT.length;

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

    @Override
    public Fragment getItem(int position) {
        //return TestFragment.newInstance(CONTENT[position % CONTENT.length]);
        return MainFragment.newInstance(position);
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
      return MainPagerAdapter.CONTENT[position % CONTENT.length];
    }

    public void setCount(int count) {
        if (count > 0 && count <= 10) {
            mCount = count;
            notifyDataSetChanged();
        }
    }


}
How to&Answers:

Another alternative is to use a OnPageChangeListener, and whenever a page change occurs call a refresh method in your fragments.

This will require you to set a higher OffScreenPageLimit, but the fragments will be updated every time one is brought into view.

pager.setOnPageChangeListener(new OnPageChangeListener() {

     @Override
     public void onPageSelected(int position){
         ((MyRefreshableFragment)pager.getAdapter().getItem(position)).refresh();
     }

     @Override
     public void onPageScrolled(int arg0, float arg1, int arg2) {}
     @Override
     public void onPageScrollStateChanged(int arg0) {}
  });

Answer:

How do I make it only load the page when the user slides to it?

Write your own ViewPager. As is noted by Jani’s answer, ViewPager has a minimum offscreen page limit of 1 to each side.

This is required for the swiping animation to work smoothly. Otherwise, if we had to wait for you to set up the UI for the next page, the user’s swipe would be frozen, or swipe to blank content, for however long it takes you to get that UI established.

Answer:

You cant do this. You will get an error like:
“Requested offscreen page limit 0 too small; defaulting to 1”. But here you can find more about it: ViewPager.setOffscreenPageLimit(0) doesn't work as expected

Answer:

I use a Loader and init the loaders of each fragment in the onPageSelected.

Answer:

I know this is very late answer but for God’s sake you do not have to write your own viewpager as someone suggested.

Lets take things from start:

How viewpager works:

By default it keeps one item in memory either side so it does not have to create it everytime.

1st Solution:

mViewPager.setOffscreenPageLimit(0);

which results to:

Requested offscreen page limit 0 too small; defaulting to 1

2nd Solution:

You want to update the Fragment when it is actually visible to the user so use the method:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
           //Do something like 
           //adapter.notifyDataSetChanged();
        }
    }

Hope it helps someone in the future!!!

Answer:

add this method in fragment

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // load data here      resumePlayer(); 
    }else{
       // fragment is no longer visible    pausePlayer();
    }
}

Answer:

there are the source code

   /**
 * 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.
 *
 * <p>This is offered as an optimization. If you know in advance the number
 * of pages you will need to support or have lazy-loading mechanisms in place
 * on your pages, tweaking this setting can have benefits in perceived smoothness
 * of paging animations and interaction. If you have a small number of pages (3-4)
 * that you can keep active all at once, less time will be spent in layout for
 * newly created view subtrees as the user pages back and forth.</p>
 *
 * <p>You should keep this limit low, especially if your pages have complex layouts.
 * This setting defaults to 1.</p>
 *
 * @param limit How many pages will be kept offscreen in an idle state.
 */
public void setOffscreenPageLimit(int limit) {
    if (limit < DEFAULT_OFFSCREEN_PAGES) {//DEFAULT_OFFSCREEN_PAGES = 1
        Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                DEFAULT_OFFSCREEN_PAGES);
        limit = DEFAULT_OFFSCREEN_PAGES;
    }
    if (limit != mOffscreenPageLimit) {
        mOffscreenPageLimit = limit;
        populate();
    }
}

you can custom your viewpager by copy the viewpager’s source, then change this method

like this

public class LazyViewPager extends ViewGroup {
private static final String TAG = "LazyViewPager";
private static final boolean DEBUG = false;

private static final boolean USE_CACHE = false;

private static final int DEFAULT_OFFSCREEN_PAGES = 0;//change default to load one page,no offset,ViewPager is 1,so cache 2 Fragment
private static final int MAX_SETTLE_DURATION = 600; // ms

Answer:

I found a solution for this after few work round. This is work perfectly.
each tab fragment class implement this code steps.

 private boolean loadData = false;

 @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (this.isVisible() && isVisibleToUser ) {
            loadData = true;
            // Load your data or call web services 
            performDataRequestAsyncTask();
        }
    }

and In onCreateView Load same data or call same web service like below

     if(!loadData && YourMainFragment.yourMainFragment.getCurrentTab() == CURRENT_TAB_INDEX){
           // Load your data or call web services 
        performDataRequestAsyncTask();
      }

In YourMainFragment which you initialize your viewrpage add this method to get currentTab

public int getCurrentTab(){
        if(mViewPager != null) return mViewPager.getCurrentItem();
        else return -1;
    }