Search code examples
androidandroid-fragmentsandroid-viewpager

Change the next page dynamically of a ViewPager


I'm using a ViewPager and displaying a lot of different Fragments inside it, not only in content but they use different classes as well. The list to be displayed should be changed dynamically and even though I manage to swap items around and add new ones to the adapter(and calling notifyDataSetChanged), if I try changing the next item it will still slide to it when using mPager.setCurrentItem(mPager.getCurrentItem() + 1);

I am just adding a new Fragment between the current item and the current next one, it is displayed correctly in the adapter but as the next one was already preloaded then getItem in the adapter is not even called.

Is there another method "stronger" than notifyDataSetChanged that tells my ViewPager that it should get the next item again?


CODE SAMPLES:

The add and get item methods inside my FragmentPagerAdapter(only samples, not the actual code)

public void add(@NonNull Integer fragmentIndex) {
    mFragmentOrder.add(fragmentIndex);
    notifyDataSetChanged();
}

@Override
public Fragment getItem(int position) {
    int selectedFragment = mFragmentOrder(position);
    Fragment fragment;

    switch (selectedFragment) {
        case 1:
            fragment = new FragmentA();
            break;
        case 2:
            fragment = new FragmentB();
            break;
        case 3:
            fragment = new FragmentC();
            break;
        default:
            fragment = new FragmentD();
            break;
    }

    return fragment;
}

This is the function used to go to the next item(I don't allow swiping)

public void goToNext() {
    mPager.setCurrentItem(mPager.getCurrentItem() + 1);
}

EDITS:

Edit 1: I had already tried using a FragmentStatePagerAdapter instead and setting the OffscreenPageLimit to 0, but to no avail.

Edit 2: [Solution] Using a FragmentStatePagerAdapter AND overwriting the getItemPosition function to return POSITION_NONE or the index in the appropriate cases solved the problem. For some reason even after implementing the right version of this function the normal FragmentPagerAdapter kept delivering the wrong Fragment.


Solution

  • By default, FragmentPagerAdapter assumes that the number and positions of its items remain fixed. Therefore, if you want to introduce for dynamism, you have to provide for it yourself by implementing the getItemPosition(Object object) method in the inherited adapter class. A very basic (but unefficient) implementation would be this:

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
    

    Every time the parent view is determining whether the position of one of its child views (items) has changed, this code will force the fragment to be recreated. If you want to avoid the recreation when unnecessary, you have to include some logic in the method. Something like this:

    @Override
    public int getItemPosition (Object object) {
        if (fragmentOrder.indexOf(object) == -1) {
            return POSITION_NONE;
        } else {
            return index;
        }
    }
    

    Finally, pay attention to possible memory leaks by adding an onDestroyView method to your fragments and nullifying the views you are using.

    Here is a good discussion of these issues with the two PagerAdapters.