Rohan
Rohan

Reputation: 593

Replace a fragment within a Viewpager(notifyDataSetChanged does not work)

My MainActivity contains a viewPager.

In the MainActivity.java, I set the adapter for viewpager. The adapter extends FragmentStatePagerAdapter. The fragment I want to replace is a cameraFragment. So when the user clicks on the switch camera button, I want to now show the camera fragment, this time with a front camera on.

On clicking the switch Camera button, I remove the fragment from the arraylist of fragments I had passed to the custom adapter. I add the new fragment and call notifydatasetchanged. However, this does not result in the new fragment being added. How do I achieve dynamic replacement of fragments within a viewpager which is backed my a custom fragment state pager adapter? Code :

mainPageFragments = new ArrayList<>();
mainPageFragments.add(new ResultsFragment_());
mainPageFragments.add(DemoCameraFragment_.newInstance(false));
pagerAdapter = new MainViewPagerAdapter(getSupportFragmentManager(),mainPageFragments);

To replace the fragment : On receiving the related event I do,

mainPageFragments.remove(1);
    if (event.getCameraState().equals(CameraSwitchButton.CameraTypeEnum.BACK)) {
        mainPageFragments.add(DemoCameraFragment.newInstance(false));
    } else {
        mainPageFragments.add(DemoCameraFragment.newInstance(true));

    }
    // Not Working...
    pagerAdapter.notifyDataSetChanged();

Adapter Code :

public class MainViewPagerAdapter extends FragmentStatePagerAdapter {

ArrayList<Fragment> fragmentsArray;

public MainViewPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragmentsArray) {
    super(fm);
    this.fragmentsArray = fragmentsArray;
}

@Override
public Fragment getItem(int position) {
    return fragmentsArray.get(position);
}

@Override
public int getCount() {
    return fragmentsArray.size();
}

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

Upvotes: 0

Views: 883

Answers (2)

Rohan
Rohan

Reputation: 593

Thanks to @Okas. I made the following change to getItemPosition within my FragmentStatePagerAdapter subclass.

@Override
 public int getItemPosition(Object object) {
    if (object instanceof DemoCameraFragment_)
        return POSITION_NONE;
    return super.getItemPosition(object);
}

I added logs to the OnCreate of both my fragments to confirm if they were getting recreated or not. As per my requirement, only the second fragment is recreated.

Upvotes: 0

Okas
Okas

Reputation: 2664

Your MainViewPagerAdapter.getItemPosition is the cause of your issue.

Default implementation always returns POSITION_UNCHANGED. For pager to remove your fragment you have to return PagerAdapter.POSITION_NONE for the fragments that are removed.

Additionally your current design contradicts with the idea of FragmentStatePagerAdapter. From the FragmentStatePagerAdapter documentation: "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."

Your current implementation holds all fragments in an array, and so defeats this mechanism. Correct implementation would be to create fragments in MainViewPagerAdapter.getItem method and let the adapter to handle fragments lifecycles as needed.

Upvotes: 2

Related Questions