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.
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.
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);
}
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.
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();
}
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;
}
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.
Appelez Viewpager.setAdapter (adaptateur); après l'élément ajouter dans votre liste de tableaux.
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;
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.