FragmentPagerAdapter notifyDataSetChanged не работает

У меня есть FragmentPagerAdapter. Его метод getItem может возвращать фрагмент в соответствии с данными, полученными извне. После того, как я обновлю данные, которые должны отображаться, я вызываю notifyDataSetChanged, но ничего не произошло. Я ДЕЙСТВИТЕЛЬНО переопределил метод getItemPosition, чтобы вернуть 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;
    }
...

И обновление извне происходит в событии клика, которое устанавливает переменную fragmentDisplayInfo. Я отладил и увидел, что fragmentDisplayInfo действительно инициализирован, а метод getItemPosition действительно возвращает POSITION_NONE, но метод getItem даже не вызывается. Это почему?

РЕДАКТИРОВАТЬ:

Если вы этого еще не сделали, обратите внимание на эту часть адаптера overiden:

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

person Yonatan Nir    schedule 06.05.2015    source источник
comment
ты нашел решение в итоге?   -  person AndroidEnthusiast    schedule 19.01.2016


Ответы (6)


Я не уверен в этом, но вы можете попробовать использовать FragmentStatePagerAdapter вместо FragmentPagerAdapter . Дело в том, что я тоже столкнулся с этой проблемой, и она мне помогла.

person Nik Myers    schedule 06.05.2015
comment
ты спас мой день! - person desidigitalnomad; 10.05.2018
comment
Как сказал Скайуокер, переопределите метод getItemPosition с возвращаемым значением POSITION_NONE, stackoverflow.com/a/36348078/2999385 - person Ahmad Vatani; 28.06.2018

То, что говорит Ник Майерс, верно. Однако не хватает куска. При вызове notifyDataSetChanged вызывается метод getItemPosition. Вам нужно переопределить это, чтобы фрагменты перезагрузились.

 @Override
    public int getItemPosition(Object object) {
        // Causes adapter to reload all Fragments when
        // notifyDataSetChanged is called
        return POSITION_NONE;
    }
person Skywalker    schedule 01.04.2016

Я столкнулся с подобной проблемой, когда работал над своим последним проектом. Поэтому я нашел несколько решений.

  1. путем переопределения getItemPosition в адаптере пейджера, но это не очень хорошая идея.

    @Override
    public int getItemPosition(Object object) {
        // it will recreate all Fragments when
        // notifyDataSetChanged is called
        return POSITION_NONE;
    }
    
  2. Второй — cabezas Solution.

  3. Наиболее стабильное решение переопределяет getItemPosition следующим образом:

        @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);
        }
    
person Ankit Saini    schedule 11.12.2017

ни одно из приведенных выше решений не работает для меня. Поэтому надеюсь, что приведенное ниже решение может быть вам полезно.

В моем коде у меня есть 2 фрагмента в viewPager. Один используется для 3 EditTexts и 1 кнопки, а другой фрагмент имеет RecyclerView. При нажатии кнопки мое значение переходит в recyclerView, но не обновляется. Итак, теперь я использовал следующий код:

введите здесь описание изображения

Я вызвал notifyDataSetChanged() при нажатии кнопки. Мой MainActivity имеет класс внутреннего адаптера, расширяющий класс FragmentStatePagerAdapter. Поэтому я вызвал его, используя mainActivity.mMainAdapter.notifyDataSetChanged(). Надеюсь, это поможет кому-то.

person Rohit Singh    schedule 06.04.2018
comment
Большой! Спасибо, что опубликовали это. Это единственное решение, которое сработало для меня - person NightStalker; 22.05.2018

Каждый ответ здесь не работал идеально для меня, но объединение нескольких ответов в один - правильный выбор.

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);
    }

}

Возвращайте POSITION_NONE только для фрагмента, который вы хотите удалить из окна просмотра. Каждый другой фрагмент все еще находится в вашем списке фрагментов. Не забудьте удалить «removeFragment» из списка перед вызовом notifyDataSetChanged();

person Orri    schedule 06.11.2018

Для тех, кто все еще сталкивается с проблемой обновления после использования вышеуказанных методов:

аннулировать viewPager, затем вызвать notifyDatatSetChanged()

person sreedwish k jagan    schedule 25.04.2020