41

I got a FragmentPagerAdapter. It's getItem method can return a fragment according to data it has from the outside. After I update the data its suppose to display I call notifyDataSetChanged and yet nothing happened. I DID override the getItemPosition method to return POSITION_NONE:

public static class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener,
        ViewPager.OnPageChangeListener
{
    private final Context mContext;
    private final TabHost mTabHost;
    private final ViewPager mViewPager;
    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
    private PagerTabsFragments fragmentDisplayInfo = null; // for now only a
                                                            // single size
                                                            // back
                                                            // stack

    static class PagerTabsFragments
    {
        public int tabPosition;
        public Fragment fragmentToDisplay;
        public Object fragmentInfo;

        public PagerTabsFragments(int tab, Fragment frag, Object info)
        {
            tabPosition = tab;
            fragmentToDisplay = frag;
            fragmentInfo = info;
        }
    }

    public void SetFragmentToDisplay(int tabPosition, Fragment frag, Object info)
    {
        fragmentDisplayInfo = new PagerTabsFragments(tabPosition, frag, info);
        notifyDataSetChanged();
    }

    public void CancelFragmentToDisplay()
    {
        fragmentDisplayInfo = null;
    }
...
@Override
    public Fragment getItem(final int position)
    {
        if ((fragmentDisplayInfo != null) && (fragmentDisplayInfo.tabPosition == position))
        {
            return fragmentDisplayInfo.fragmentToDisplay;
        }
        final TabInfo info = mTabs.get(position);
        return Fragment.instantiate(mContext, info.clss.getName(), info.args);
    }

    @Override
    public int getItemPosition(Object item)
    {
        if (fragmentDisplayInfo == null)
        {
            return super.getItemPosition(item);
        }
        return POSITION_NONE;
    }
...

And the update from outside is in a click event which sets the fragmentDisplayInfo var. I debuged and saw that the fragmentDisplayInfo is indeed initialized and the getItemPosition method does return POSITION_NONE, but the getItem method is not even called. Why is that?

EDIT:

If you hadn't done so as well, please notice that overiden part of the adapter:

 @Override
public int getItemPosition(Object item)
{
    return POSITION_NONE;
}
Yonatan Nir
  • 8,303
  • 23
  • 80
  • 156

6 Answers6

77

What Nik Myers is saying is correct. However there is a piece missing. When notifyDataSetChanged is called, the method getItemPosition is called. You need to override this to get the fragments to reload.

 @Override
    public int getItemPosition(Object object) {
        // Causes adapter to reload all Fragments when
        // notifyDataSetChanged is called
        return POSITION_NONE;
    }
Skywalker
  • 1,509
  • 18
  • 23
55

I'm not sure about this, but you can try to use FragmentStatePagerAdapter instead of FragmentPagerAdapter . The thing is, i've also run into this issue, and it helped me

Nik Myers
  • 1,773
  • 15
  • 28
5

I have faced the similar problem when I was working on my last project. So I found few Solution.

  1. by overriding getItemPosition in the pager adaptor but this is not a good idea.

    @Override
    public int getItemPosition(Object object) {
        // it will recreate all Fragments when
        // notifyDataSetChanged is called
        return POSITION_NONE;
    }
    
  2. The second one is cabezas Solution.

  3. Most Stable solution override getItemPosition in below fashion:

        @Override
        public int getItemPosition(Object object) {
            if (object instanceof MyFragment) {
                // Create a new method notifyUpdate() in your fragment 
                // it will get call when you invoke 
                // notifyDatasetChaged();
                ((MyFragment) object).notifyUpdate();
            }
            //don't return POSITION_NONE, avoid fragment recreation.
            return super.getItemPosition(object);
        }
    
Ankit Saini
  • 357
  • 5
  • 14
1

none of the solutions given above works for me. So hope below solution may be helpful for you.

In my code, I have 2 Fragments in viewPager. One is used for 3 EditTexts and 1 button and another fragment has RecyclerView. On button click, my value is going to recyclerView, but it's not updating. So now, I used the below code:

enter image description here

I called the notifyDataSetChanged() on button click. My MainActivity has inner adapter class extends FragmentStatePagerAdapter class. So i called it using mainActivity.mMainAdapter.notifyDataSetChanged(). Hope it helps someone.

Rohit Singh
  • 326
  • 2
  • 15
1

Every answer here did not work perfectly for me but combining multiple answers into one is right choice.

public final class SomeFragment extends FragmentStatePagerAdapter{
    private final List<Fragment> fragments;
    private Fragment removeFragment; //Fragment to be removed in the next notifydatasetchanged


    @Override
    public int getItemPosition(final Object object) {
       return object.equals(this.removeFragment) ? FragmentStatePagerAdapter.POSITION_NONE : this.fragments.indexOf(object);
    }

}

Return POSITION_NONE only for the fragment you would like to remove from the viewpager. Every other fragment is still in your fragment list. Do not forget to remove the "removeFragment" from the list before calling notifyDataSetChanged();

Orri
  • 901
  • 1
  • 8
  • 20
0

For those who still facing refresh issue after trying above methods :

invalidate viewPager then call notifyDatatSetChanged()