PagerAdapter.notifyDataSetChanged does not refresh fragments

android refresh fragment pager adapter
updating viewpager with new data dynamically
android-viewpager with one fragment
android-viewpager refresh current page
fragment state pager adapter notifydatasetchanged
viewpager adapter not working
refresh fragment inside viewpager
how to clear viewpager adapter in android

My Activity contains a ViewPager and it's custom Adapter which extends FragmentStatePagerAdapter. ViewPager contains 3 fragments

Code to remove Fragments from the 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);
}

when removing the middle Fragment (index 1):

  • from data i'm removing the correct item.
  • Problem is that i (i guess) Fragment 3 is removed after notifyDataSetChanged and the current Fragment is still the fragment that the user saw and the data that is being loaded is from the SavedInstance bundle

So the end result that the user still see the same Fragment that he tried to remove which is kinda suck for him.

Ideas?

***** EDIT ******

seems like ViewPager2 Features might solve this issue and many other issues as well

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

PagerAdapter.notifyDataSetChanged does not refresh fragments, Try adding this: private class MyPagerAdapter extends FragmentStatePagerAdapter { // your existing code @Override public int getItemPosition(Object object){  Home » Android » android – PagerAdapter.notifyDataSetChanged does not refresh fragments android – PagerAdapter.notifyDataSetChanged does not refresh fragments Posted by: admin May 11, 2020 Leave a comment

Try adding this:

private class MyPagerAdapter extends FragmentStatePagerAdapter {

//... your existing code

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

}

ViewPager PagerAdapter not updating the View, public class ViewPagerAdapter extends PagerAdapter { // Members private the fix is to return POSITION_NONE right after the notifyDataSetChanged() was called below is the code which has to be written in first fragment (in my case) i-e in  When an ArrayAdapter or BaseAdapter are constructed, it holds the reference for the List that was passed in. If you were to pass in a List that was a member of an Activity, and change that Activity member later, the ArrayAdapter is still holding a reference to the original List. The Adapter does not know you changed the List in the Activity.

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, 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
    }
}

Updating ViewPager With New Data Dynamically, If you have to show custom views (not Fragments) then subclass it and it will not gets updated by calling notifyDataSetChanged() method. I m using Tablayout with ViewPagerAdapter. For passing data between fragments or for communicating between fragments use below code which works perfectly fine and refresh the fragment when ever it appears. Inside button click of second fragment write below code.

You can try to use FragmentPagerAdapter instead of FragmentStatePagerAdapter. The thing is, i have also run into this issue, and it helped me.

notifyDataSetChanged not working · Issue #1 · takaaki7 , I want to change background of fragment which is on viewpager but it @​viksoffice i'm also stuck with updating viewpager , can you help me  And when you go to a tab 3 or 4, then your 2 firsts fragments are deleted, then recreated when you come back. To refresh your fragment, there is many way to do it: you could implement a listener interface of your own in it to tell it when to refresh, or simply call a method that you would implement to update your contents.

You have to first set the adapter to null and then set it back:

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

ViewPager with FragmentPagerAdapter, A ViewPager is a layout which can be added to any layout XML file inside a root a reload } else { // POSITION_NONE means something like: this fragment is no then invoke notifyDataSetChanged on the pager adapter to trigger a reload of  FragmentManager does not hold the fragments which are going off the screen and simply destroys it. In this way new fragments gets new data from the object collection directly. Same thing is true for PagerAdapter as well and we only override getItemPosition() in order to update the view with new data because FragmentPager also destroys the views

Migrate from ViewPager to ViewPager2, This means that your app can dynamically modify the fragment collection at runtime, and ViewPager2 will Adapter do not require a constructor parameter. Not really; getItemPosition is used to notify the ViewPager whether or not to refresh an item, and to avoid updates if the items at the visible positions haven't changed. The "bug" here is the non-obvious and/or non-existent solution to refresh the visible items from client code. – tad Oct 5 '11 at 6:55

FragmentPagerAdapter doesnt reload Tabs : androiddev, It works, but sometimes the tabs that should be displayed change. When this happens, notifyDataSetChanged() is called. The reason it doesn't refresh is because the default destroyItem() only detaches the Fragment so when I made a two piece article on how to build an app without third party libs, by starting the app  (1) @AlexTran If you are using fragments i will not recommend using PagerAdapter, as a Fragment does not provide setTag method. Use in this case a FragmentPagerAdapter or FragmentPagerStateAdapter. - Alvaro Luis Bustamante

Adventures with FragmentStatePagerAdapter - INLOOPX, Also getting notifyDatasetChanged() to work can be… gotchas (did you know that Fragments in FragmentPagerAdapter are only released from Doing so will not refresh the current visible fragments and you have to swipe  Dynamic ViewPager Fragments. In certain cases, we may require a dynamic ViewPager where we want to get access to fragment instances or with pages being added or removed at runtime. If your ViewPager is more dynamic with many pages and fragments, we will want to use an implementation of the alternate FragmentStatePagerAdapter instead. Below

Comments
  • I would suggest switching to my ArrayPagerAdapter, which handles this. I am not terribly surprised that FragmentStatePagerAdapter has problems in this area, which is why I rolled something separate.
  • Try this
  • Good simple solution: stackoverflow.com/a/35450575/2162226
  • @gnB this is not a solution to this problem
  • Please add an example of how to remove data and I will approve your answer. Thanks!
  • I just edited my answer to show how to remove the item. I also add the getItemId method in the adapter, it might be needed by the adapter to monitor the changes
  • According to the JavaDoc of getItemId(int) you should also override containsItem(long) When overriding, also override {@link #containsItem(long)}.
  • but then it will cause android to restart all my fragments which is kind of pointless no?
  • Yes, here others options
  • i know about those 2 options and i saw those posts before asking the question. the problem is that i'm not updating a view but removing one. i can't be sure which view will be removed thus calling fragment by tag is not really safe (maybe it's already destroyed? should i update all other fragments?)
  • Thanks its work for me: extends FragmentStatePagerAdapter
  • single-line solution should be posted in comment.
  • int getItemPosition(Object object) { return POSITION_NONE; }