PagerAdapter.notifyDataSetChanged does not refresh fragments
You have no choice but to implement PagerAdapter#getItemPosition
. Looking at the source that's exactly how ViewPager determines how to update its position, add new fragments or drop dead ones after notifyDataSetChanged
. It shouldn't be too hard, you just need to access the state of the passed fragment, and you also need to access the master state in your activity which holds your ordering.
It's also required you implement getItemId
to return a consistent ID for each fragment, because they can be reordered.
This is how I handled it in a ViewPager of photos.
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]
}
}
You can try to use FragmentPagerAdapter instead of FragmentStatePagerAdapter. The thing is, i have also run into this issue, and it helped me.
I know this question is a bit old, but it might be interesting to know that Google recently solved this problem with ViewPager2. See examples here
First of all, a the following dependency in your build.gradle file :
dependencies {
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
}
Now you can replace your ViewPager in your xml file with :
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
Then you will need to replace ViewPager by ViewPager2 in your activity
ViewPager2 needs either a RecycleView.Adapter, or a 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
}
}
In the case you were using a TabLayout, you can use a 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();
In order to remove data, after removing the item from your collection you can either call the notifyDataSetChanged()
method or more specifically the notifyItemRemoved()
with the position of removed item
Try adding this:
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
@Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
}