提问者:小点点

PagerAdapter.NotifyDataSetChanged不刷新片段


我的activity包含一个ViewPager和它的自定义适配器,该适配器扩展了FragmentStatePagerAdapterViewPager包含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);
}

删除中间的片段(索引1)时:

  • 数据中删除正确的
  • 问题是,在NotifyDataSetChanged之后,我(我猜)fragment3被删除,当前的片段仍然是用户看到的片段,并且正在加载的数据来自SavedInstance

所以最终结果是,用户仍然看到他试图删除的相同的片段,这对他来说有点糟糕。

想法?

*****编辑******

似乎ViewPager2的特性可以解决这个问题以及许多其他问题


共3个答案

匿名用户

我知道这个问题有点老了,但是知道Google最近用ViewPager2解决了这个问题可能会很有趣。请参阅此处的示例

首先,在build.gradle文件中存在以下依赖项:

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

现在您可以将xml文件中的ViewPager替换为:

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

则需要在activity中将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()

匿名用户

尝试添加以下内容:

private class MyPagerAdapter extends FragmentStatePagerAdapter {

//... your existing code

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

}

匿名用户

您别无选择,只能实现PagerAdapter#GetItemposition。查看源代码,这正是ViewPager确定如何在NotifyDataSetChanged之后更新其位置,添加新片段或删除已死亡片段的方式。这应该不会太难,您只需要访问传递的片段的状态,并且您还需要访问保存您的排序的activity中的主状态。

还需要实现GetItemId为每个片段返回一致的ID,因为它们可以重新排序。

这是我如何处理它在一个取景器的照片。

    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, this@PhotoPagerActivity.photos[position])
    }

    override fun getItemId(position: Int): Long {
        return this@PhotoPagerActivity.photos[position].ID!!.hashCode().toLong()
    }

    override fun getItemPosition(`object`: Any): Int {
        val frag = `object` as PhotoViewFragment
        val idx = this@PhotoPagerActivity.photos.indexOfFirst { ph -> ph.ID == frag.dataBinding.photo.ID }
        return if (idx >= 0) idx else PagerAdapter.POSITION_NONE
    }

    override fun getCount(): Int {
        return this@PhotoPagerActivity.photos.size
    }
}