IllegalStateException: The application's PagerAdapter changed the adapter's content without calling PagerAdapter#notifyDataSetChanged
Asked Answered
B

10

42

I'm using the ViewPager example with ActionBar tabs taken from the Android documentation here.

Unfortunately, as soon as I call the addTab method, the application crashes with the following exception:

IllegalStateException: The application's PagerAdapter changed the adapter's content without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count 0, found 1.

This is the FragmentPagerAdapter code:

public static class TabsAdapter extends FragmentPagerAdapter
            implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
        private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

        static final class TabInfo {
            private final Class<?> clss;
            private final Bundle args;

            TabInfo(Class<?> _class, Bundle _args) {
                clss = _class;
                args = _args;
            }
        }

        public TabsAdapter(Activity activity, ViewPager pager) {
            super(activity.getFragmentManager());
            mContext = activity;
            mActionBar = activity.getActionBar();
            mViewPager = pager;
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(this);
        }

        public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
            TabInfo info = new TabInfo(clss, args);
            tab.setTag(info);
            tab.setTabListener(this);
            mTabs.add(info);
            mActionBar.addTab(tab);
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return mTabs.size();
        }

        @Override
        public Fragment getItem(int position) {
            TabInfo info = mTabs.get(position);
            return Fragment.instantiate(mContext, info.clss.getName(), info.args);
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            mActionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            Object tag = tab.getTag();
            for (int i=0; i<mTabs.size(); i++) {
                if (mTabs.get(i) == tag) {
                    mViewPager.setCurrentItem(i);
                }
            }
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
        }
    }
}

I'm not modifying my adapter in any other part of my code and I'm calling the addTab method from the main thread, the addTab method ends with a call to notifyDataSetChanged. As the documentation recommends to do:

PagerAdapter supports data set changes. Data set changes must occur on the main thread and must end with a call to notifyDataSetChanged() similar to AdapterView adapters derived from BaseAdapter.

Burthen answered 8/4, 2014 at 17:2 Comment(0)
B
30

I had a hard time making my ViewPager working. At the end, it seems that the example in the documentation is wrong.

The addTab method should be as follows:

public void addTab(Tab tab, Class<?> clss, Bundle args) {
        TabInfo info = new TabInfo(clss, args);
        tab.setTag(info);
        tab.setTabListener(this);
        mTabs.add(info);
        notifyDataSetChanged();
        mActionBar.addTab(tab);
    }

Notice the order of the last three operations. In the original example, notifyDataSetChanged was called after the mActionBar.addTab function.

Unfortunately, as soon as you call the addTab on the ActionBar, the first tab you add is automatically selected. Because of this, the onTabSelected event is fired and while trying to retrieve the page, it throws the IllegalStateException because it notices a discrepancy between the expected item count and the actual one.

Burthen answered 8/4, 2014 at 17:2 Comment(1)
I've been looking for this for a while. Am I the only one who finds it odd that the error reads as if I am not calling notifyDataSetChanged(), when really I need to just perform the action(setCurrentItem in my case) After notifyDataSetChanged()?Ever
F
13

I fixed it by callinig notifyDataSetChanged() once and just before next call of getCount():

private boolean doNotifyDataSetChangedOnce = false;

@Override
public int getCount() {

  if (doNotifyDataSetChangedOnce) {
    doNotifyDataSetChangedOnce = false;
    notifyDataSetChanged();
  }

  return actionBar.getTabCount();

}

private void addTab(String text) {

  doNotifyDataSetChangedOnce = true;

  Tab tab = actionBar.newTab();
  tab.setText(text);
  tab.setTabListener(this);
  actionBar.addTab(tab);

}

private void removeTab(int position) {

  doNotifyDataSetChangedOnce = true;

  actionBar.removeTabAt(position);

}
Fifty answered 26/9, 2014 at 14:13 Comment(0)
C
3

I was getting this error like you by referencing the tabs within getCount():

@Override
    public int getCount() {
        return mTabs.size();
    }

When instantiated this should either be passed in as a separate variable, or the pager should be set up after the collection has been populated / mutated.

Carpio answered 2/10, 2015 at 13:43 Comment(0)
T
2

try this. I worked

protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            System.out.println("Asyncrona onPostExecute");
            /*::::::::::::::::::: Guardo los cambios  ::::::::::::::*/
            //menuTabs = menuTabs2;
            viewPager = (ViewPager) rootView.findViewById(R.id.viewPager_menu);
            costumAdapter = new CostumAdapter2(getActivity().getSupportFragmentManager());
            costumAdapter.notifyDataSetChanged();

            viewPager.setAdapter(costumAdapter);
            tabLayout = (TabLayout) rootView.findViewById(R.id.tablayout_menu);
            tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    System.out.println(" La Seleccionado: " + tab.getText()+", POSICION: "+tab.getPosition());
                    viewPager.setCurrentItem(tab.getPosition());
                }

                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
                    viewPager.setCurrentItem(tab.getPosition());
                }

                @Override
                public void onTabReselected(TabLayout.Tab tab) {
                    viewPager.setCurrentItem(tab.getPosition());
                }

            });
            viewPager.setAdapter(costumAdapter);
            tabLayout.setupWithViewPager(viewPager);
            loading.closeMessage();

        }
Thebaine answered 20/4, 2017 at 16:37 Comment(0)
M
0

I had the same problem in FragmentStatePager adapter. in onResume() When reInitialize the adpater and ViewPager, the same error IllegalStateException will be shown. The solution:

When adding tab addtab, choose the tab to be not selected by setting setSelected params to false.

 actionBar.addTab(tab,false);

I think the exception appeared because of overriding the onTabSelected() method like the following

 viewPager.setCurrentItem(tab.getPosition());

So when calling addTab() it didn't recognize which viewPager and adapter to add the tab to.

Mcnulty answered 24/8, 2015 at 14:40 Comment(0)
A
0

My issue wasn't exactly the same, but similar context.

I have an AlertDialog getting shown in a layout that has ViewPager and is using AppCompatActivity. I was getting the IllegalStateException and crash when rotating the screen.

Thanks to the answers from answer @almisoft and @Zagorax, I tried calling notifyDataSetChanged(); right before I show the dialog, and the problem seems to have gone away.

Awoke answered 12/11, 2015 at 22:1 Comment(1)
notifyDataSetChanged() didn't work for meColburn
A
0

add this line into your adapter file where the public Object instantiateItem(ViewGroup container, int position) method is called

((ViewPager) container).addView(view); return view;

Alexandro answered 3/5, 2018 at 11:14 Comment(0)
O
0

Make sure the values in setOffscreenPageLimit and getCount match, otherwise you will get this error:

    mViewPager.setOffscreenPageLimit(MAX_TABS);

    public class SectionsPagerAdapter extends FragmentPagerAdapter {
    ...
    @Override
    public int getCount() {
        return MAX_TABS;
    }
Ogpu answered 7/8, 2018 at 16:27 Comment(0)
D
0

Call Viewpager.setAdapter(adapter); after item add in your array list.

Donelladonelle answered 11/6, 2019 at 9:52 Comment(0)
S
0

One more thing to be check here is the adapter for which it gives this error check source list is getting reference from other list or not.

It is possible that your adapter list is referenced from other list and in that list got update and added some items.

Sapajou answered 27/10, 2020 at 7:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.