Home » Android » android – ViewPager.setOffscreenPageLimit(0) doesn't work as expected

android – ViewPager.setOffscreenPageLimit(0) doesn't work as expected

Posted by: admin March 11, 2020 Leave a comment

Questions:

The fragments I use in my ViewPager instance are quite resource intensive, so I’d only like to load one at a time. When I try the following:

mViewPager.setOffscreenPageLimit(0);
mViewPager.setAdapter(mPagerAdapter);

My FragmentStatePagerAdapter.getItem(int position) override function is called 3 times, which is what happens when I call mViewPager.setOffscreenPageLimit(1). I would expect it to only be called once, because I specified 0 offscreen pages.

I believe I’m calling everything correctly, because if I call mViewPager.setOffscreenPageLimit(2), FragmentStatePagerAdapter.getItem(int position) is called 5 times as I would expect.

Does ViewPager require a minimum of 1 offscreen pages, or am I doing something wrong here?

How to&Answers:

Does ViewPager require a minimum of 1 offscreen pages

Yes. If I am reading the source code correctly, you should be getting a warning about this in LogCat, something like:

Requested offscreen page limit 0 too small; defaulting to 1

Answer:

The best way that I found was setUserVisibleHint
add this to your fragment

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

Answer:

You can try like this :

public abstract class LazyFragment extends Fragment {
    protected boolean isVisible;
    /**
     * 在这里实现Fragment数据的缓加载.
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if(getUserVisibleHint()) {
            isVisible = true;
            onVisible();
        } else {
            isVisible = false;
            onInvisible();
        }
    }
    protected void onVisible(){
        lazyLoad();
    }
    protected abstract void lazyLoad();
    protected void onInvisible(){}
protected abstract void lazyLoad();
protected void onInvisible(){}

Answer:

First Add

   boolean isFragmentLoaded = false;

than

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser && !isFragmentLoaded) {
        //Load Your Data Here like.... new GetContacts().execute();

        isFragmentLoaded = true;
    }
else{
     }
}

Answer:

ViewPager is default to load the next page(Fragment) which you can’t change by setOffscreenPageLimit(0). But you can do something to hack.
You can implement onPageSelected function in Activity containing the ViewPager. In the next Fragment(which you don’t want to load), you write a function let’s say showViewContent() where you put in all resource consuming init code and do nothing before onResume() method. Then call showViewContent() function inside onPageSelected. Hope this will help.

Answer:

in my case i wanted to start some animations in views, but with setUserVisibleHint got some issues …
my solution is :

1/ addOnPageChangeListener for your adapter :

mViewPager.addOnPageChangeListener(this);

2/ implement OnPageChangeListener :

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3/ override the 3 methodes :

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4/ declare and initialize this variable on your class

private static int mTabState = 1;

notice : i have three fragments in my adapter, and use mTabState for setCurrentItem and current position of adapter which recognize which fragment is show to user in time …
5/ in onPageSelected method add this codes :

if (mTabState == 0 || position == 0)
    {
        Intent intent = new Intent("animation");
        intent.putExtra("current_position", position);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }

if previous page or current page is page 0(fragment in position 0) then do this stuff

6/ now in your fragment class (fragment in position 0 of adapter), you must create broadcast receiver and register it in onResume method and unregister it onPause methos :

BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (Objects.equals(intent.getAction(), "animation"))
        {
            int currentPosition = intent.getIntExtra("current_position", 0);
            if (currentPosition == 0)
            {
                startAnimation();
                setViewsVisible();
            } else
            {
                setViewsInvisible();
            }
        }
    }
};

@Override
public void onResume()
{
    super.onResume();
    LocalBroadcastManager.getInstance(mContext).registerReceiver(broadcastReceiver, new IntentFilter("animation"));
}

@Override
public void onPause()
{
    super.onPause();
    LocalBroadcastManager.getInstance(mContext).unregisterReceiver(broadcastReceiver);
}

summary : i have Fragment Pager Adapter witch shows Three Fragments in it, I want show some Animations on Views in Fragment in Position 0 of Adapter, For this I use BroadcastReceiver. When Fragment is Picked I start the Animation method and shows the Views to User, When Fragment is not Showing to User I try to Invisible Views…

Answer:

Please Try This Code for resolve issue of refreshing view in Viewpager….

/* DO NOT FORGET! The ViewPager requires at least “1” minimum OffscreenPageLimit */
int limit = (mAdapter.getCount() > 1 ? mAdapter.getCount() - 1 : 1);
mViewPager.setOffscreenPageLimit(limit);

Answer:

for the “instantiateItem” function, just prepare the fragment, but don’t load the heavy content.

Use “onPageChangeListener” , so that each time you go to a specific page, you load its heavy content and show it.

Answer:

this may be old thread but this seems to work for me. Override this function :

@Override
public void setMenuVisibility(boolean menuVisible) { 
    super.setMenuVisibility(menuVisible);

    if ( menuVisible ) {
        /**
         * Load your stuffs here.
         */
    } else  { 
        /**
         * Fragment not currently Visible.
         */
    } 
}

happy codings…

Answer:

I kind of have the same problem. I found some useful code on this site and transform it.

The min int for mViewPager.setOffscreenPageLimit(…); is 1, so even if you change it to 0 you will still have 2 pages loaded.

First thing to do is to create a static int we will call maxPageCount and override FragmentStatePagerAdapter method getCount() to return maxPageCount:

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

Create then a static method accessible from any where in the program that will allow you to change this maxCount:

public static void addPage(){
    maxPageCount++; //or maxPageCount = fragmentPosition+2
    mFragmentStatePagerAdapter.notifyDataSetChanged(); //notifyDataSetChanged is important here.
}

Now initialize maxPageCount to 1. When ever you want you can add another page.
In my case when I needed the user to treat the current page first before generated the other. He do it and then, without problem can swipe to the next page.

Hope it help someone.

Answer:

Use This
// create boolean for fetching data
private boolean isViewShown = false;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getView() != null) {
        isViewShown = true;
        // fetchdata() contains logic to show data when page is selected mostly asynctask to fill the data
        fetchData();
    } else {
        isViewShown = false;
    }
}