web-dev-qa-db-fra.com

IllegalStateException: le PagerAdapter de l'application a changé le contenu de l'adaptateur sans appeler PagerAdapter # notifyDataSetChanged

J'utilise l'exemple ViewPager avec les onglets ActionBar tirés de la documentation Android ici .

Malheureusement, dès que j'appelle la méthode addTab, l'application se bloque avec l'exception suivante:

IllegalStateException: le PagerAdapter de l'application a changé le contenu de l'adaptateur sans appeler PagerAdapter # notifyDataSetChanged! Nombre d'éléments d'adaptateur attendu 0, trouvé 1.

Voici le code FragmentPagerAdapter:

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) {
        }
    }
}

Je ne modifie mon adaptateur dans aucune autre partie de mon code et j'appelle la méthode addTab à partir du thread principal, la méthode addTab se termine par un appel à notifyDataSetChanged. Comme la documentation le recommande:

PagerAdapter prend en charge les modifications d'ensemble de données. Les modifications de l'ensemble de données doivent se produire sur le thread principal et doivent se terminer par un appel à notifyDataSetChanged () similaire aux adaptateurs AdapterView dérivés de BaseAdapter.

38
Zagorax

J'ai eu du mal à faire fonctionner mon ViewPager. Au final, il semble que l'exemple de la documentation soit erroné.

La méthode addTab doit être la suivante:

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);
    }

Notez l'ordre des trois dernières opérations. Dans l'exemple d'origine, notifyDataSetChanged a été appelé après le mActionBar.addTab une fonction.

Malheureusement, dès que vous appelez le addTab sur le ActionBar, le premier onglet que vous ajoutez est automatiquement sélectionné. De ce fait, l'événement onTabSelected est déclenché et lors de la tentative de récupération de la page, il lève IllegalStateException car il constate une différence entre le nombre d'éléments attendu et le nombre réel.

25
Zagorax

Je l'ai corrigé par callinig notifyDataSetChanged () une fois et juste avant le prochain appel de 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);

}
12
almisoft

J'obtenais cette erreur comme vous en référençant les onglets dans getCount ():

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

Lorsqu'il est instancié, cela doit être transmis en tant que variable distincte, ou le pager doit être configuré après la collection a été remplie/mutée.

3
Daniel Wilson

essaye ça. J'ai travaillé

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();

        }
2
Isa M

Assurez-vous que les valeurs de setOffscreenPageLimit et getCount correspondent, sinon vous obtiendrez cette erreur:

    mViewPager.setOffscreenPageLimit(MAX_TABS);

    public class SectionsPagerAdapter extends FragmentPagerAdapter {
    ...
    @Override
    public int getCount() {
        return MAX_TABS;
    }
0
live-love

Mon problème n'était pas exactement le même, mais un contexte similaire.

J'ai un AlertDialog affiché dans une mise en page qui a ViewPager et utilise AppCompatActivity. J'obtenais l'exception IllegalStateException et je plantais lors de la rotation de l'écran.

Grâce aux réponses de answer @almisoft et @Zagorax, j'ai essayé d'appeler notifyDataSetChanged(); juste avant d'afficher la boîte de dialogue, et le problème semble avoir disparu.

0
Gene Bo

Appelez Viewpager.setAdapter (adaptateur); après l'élément ajouter dans votre liste de tableaux.

0
Vibhu Vikram Singh

ajoutez cette ligne dans votre fichier adaptateur où la méthode publique Object instantiateItem (conteneur ViewGroup, position int) est appelée

(Conteneur (ViewPager)) .addView (view); vue de retour;

0
Dhaval Barot

J'ai eu le même problème dans l'adaptateur FragmentStatePager. dans onResume() Lorsque vous réinitialisez l'adpateur et ViewPager, la même erreur IllegalStateException sera affichée. La solution:

Lors de l'ajout de l'onglet addtab, choisissez l'onglet à ne pas sélectionner en définissant setSelected params sur false.

 actionBar.addTab(tab,false);

Je pense que l'exception est apparue en raison de la substitution de la méthode onTabSelected() comme la suivante

 viewPager.setCurrentItem(tab.getPosition());

Ainsi, lors de l'appel de addTab(), il n'a pas reconnu le viewPager et l'adaptateur auxquels ajouter l'onglet.

0
Amt87