Подтвердить что ты не робот

PagerAdapter.notifyDataSetChanged не обновляет фрагменты

Мой Activity содержит ViewPager и пользовательский Adapter, который расширяет FragmentStatePagerAdapter. ViewPager содержит 3 фрагмента

Код для удаления фрагментов из ViewPager

MainActivity

public void deleteElement(){
    final int currentItem = mViewPager.getCurrentItem();
    mPagerAdapter.removeItem(currentItem);
    mPagerAdapter.notifyDataSetChanged();
}

CustomPagerAdapter

private ArrayList<Item> data;
public void removeItem(int index){
        data.remove(index);
}

при удалении середины Fragment (индекс 1):

  • из data я удаляю правильный item.
  • Проблема в том, что я (я думаю) Fragment 3 удаляется после notifyDataSetChanged, а текущий Fragment по-прежнему является фрагментом, который видел пользователь, и загружаемые данные из пакета SavedInstance

Таким образом, конечный результат заключается в том, что пользователь все еще видит тот же самый Fragment, который он пытался удалить, что для него отстой.

Идеи?

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

Похоже, ViewPager2 Возможности могут решить эту проблему, а также многие другие проблемы

4b9b3361

Ответ 1

Я знаю, что этот вопрос немного устарел, но было бы интересно узнать, что Google недавно решил эту проблему с помощью ViewPager2. Смотрите примеры здесь

Прежде всего, существует следующая зависимость в вашем файле build.gradle:

  dependencies {
     implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
  }

Теперь вы можете заменить ваш ViewPager в своем XML файле на:

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

Затем вам нужно будет заменить ViewPager на ViewPager2 в своей деятельности

ViewPager2 требуется либо RecycleView.Adapter, либо FragmentStateAdapter:

    public class TabAdapter extends FragmentStateAdapter {
        private final List<Tab> tabs;

        public TabAdapter(@NonNull FragmentManager fm, List<Tab> tabs, Lifecycle lifecycle) {
            super(fm, lifecycle);

            this.tabs = tabs;
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            //create your fragment here
        }

        @Override
        public int getItemCount() {
            return tabs.size();
        }

        @Override
        public long getItemId(int position) {
            // use a distinct id for each item to allow the adapter to see the changes
        }
    }

Если вы использовали TabLayout, вы можете использовать TabLayoutMediator:

        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
            @Override
            public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
                // configure your tab here
                tab.setText(tabs.get(position).getTitle());
            }
        });

        tabLayoutMediator.attach();

Чтобы удалить данные, после удаления элемента из вашей коллекции вы можете вызвать метод notifyDataSetChanged() или, более конкретно, notifyItemRemoved() с позицией удаленного элемента.

Ответ 2

Попробуйте добавить это:

private class MyPagerAdapter extends FragmentStatePagerAdapter {

//... your existing code

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

}

Ответ 3

У вас нет выбора, кроме как реализовать PagerAdapter#getItemPosition. Рассматривая источник, как именно ViewPager определяет, как обновить свою позицию, добавить новые фрагменты или отбросить мертвые после notifyDataSetChanged. Это не должно быть слишком сложно, вам просто нужно получить доступ к состоянию переданного фрагмента, и вам также нужно получить доступ к главному состоянию в вашей деятельности, которая поддерживает ваше упорядочение.

Также потребовалось реализовать getItemId, чтобы вернуть согласованный идентификатор для каждого фрагмента, потому что они могут быть переупорядочены.

Вот как я обработал его в ViewPager фотографий.

    private inner class PhotoPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
    override fun getItem(position: Int): PhotoViewFragment {
        // getItem is called to instantiate the fragment for the given page.
        return PhotoViewFragment.newInstance(position, [email protected][position])
    }

    override fun getItemId(position: Int): Long {
        return [email protected][position].ID!!.hashCode().toLong()
    }

    override fun getItemPosition(`object`: Any): Int {
        val frag = `object` as PhotoViewFragment
        val idx = [email protected] { ph -> ph.ID == frag.dataBinding.photo.ID }
        return if (idx >= 0) idx else PagerAdapter.POSITION_NONE
    }

    override fun getCount(): Int {
        return [email protected]
    }
}

Ответ 4

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

Ответ 5

Вы должны сначала установить адаптер на ноль, а затем установить его обратно:

int currentPosition = mViewPager.getCurrentItem();
mPagerAdapter.notifyDataSetChanged();
mViewPager.setAdapter(null);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(currentPosition);

Ответ 6

Вы можете попробовать использовать FragmentStatePagerAdapter вместо публичного FragmentPagerAdapter

Его работа для меня..!