26

sto usando l'esempio ViewPager con ActionBar schede tratte dalla documentazione di Android here.IllegalStateException: PagerAdapter L'dell'applicazione cambiato il contenuto della scheda senza chiamare PagerAdapter # notifyDataSetChanged

Purtroppo, non appena chiamo il metodo addTab, l'applicazione si blocca con la seguente eccezione:

IllegalStateException: PagerAdapter L'dell'applicazione cambiato il contenuto della scheda senza chiamare PagerAdapter # notifyDataSetChanged! Previsto conteggio degli elementi adattatore 0, trovato 1.

Questo è il codice 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) { 
     } 
    } 
} 

non sto modificando il mio adattatore in qualsiasi altra parte del mio codice e sto chiamando il addTab metodo dal thread principale, il metodo addTab termina con una chiamata a notifyDataSetChanged. Come suggerisce la documentazione:

PagerAdapter supporta le modifiche del set di dati. Le modifiche al set di dati devono essere eseguite su il thread principale e devono terminare con una chiamata a notifyDataSetChanged() simile agli adattatori AdapterView derivati ​​da BaseAdapter.

risposta

18

Ho avuto difficoltà a rendere operativo il mio ViewPager. Alla fine, sembra che l'esempio nella documentazione sia sbagliato.

Il metodo addTab dovrebbe essere la seguente:

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

Avviso l'ordine delle ultime tre operazioni. Nell'esempio originale, notifyDataSetChanged è stato chiamato dopo la funzione mActionBar.addTab.

Sfortunatamente, non appena si chiama addTab su ActionBar, la prima scheda aggiunta viene selezionata automaticamente. Per questo motivo, l'evento onTabSelected viene generato e durante il tentativo di recuperare la pagina, esso immette lo IllegalStateException perché rileva una discrepanza tra il numero di elementi previsto e quello effettivo.

+0

Ho cercato per questo per un po '. Sono l'unico che trova strano che l'errore si legge come se non stessi chiamando notifyDataSetChanged(), quando in realtà ho solo bisogno di eseguire l'azione (setCurrentItem nel mio caso) After notifyDataSetChanged()? – wizurd

8

ho riparato da callinig notifyDataSetChanged() una volta e poco prima della prossima chiamata 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); 

} 
+0

Roba buona qui ... grazie! – worked

0

Ho avuto lo stesso problema in FragmentStatePager adattatore. in onResume() Quando si reinizializza l'adpatore e ViewPager, verrà visualizzato lo stesso errore IllegalStateException. La soluzione:

Quando si aggiunge la scheda addtab, selezionare la scheda da non selezionare impostando setSelected params su false.

actionBar.addTab(tab,false); 

penso che l'eccezione è apparso a causa di override del metodo onTabSelected() simile al seguente

viewPager.setCurrentItem(tab.getPosition()); 

Così quando si chiama addTab() non riconosceva che viewPager e l'adattatore per aggiungere la scheda a.

3

stavo ottenendo questo errore come te facendo riferimento alle schede all'interno getCount():

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

Quando un'istanza questo dovrebbe neanche essere passato come una variabile indipendente, o il pager dovrebbe essere istituito dopo la collezione è stata popolata/mutata.

0

Il mio problema non era esattamente lo stesso, ma un contesto simile.

Ho un AlertDialog che viene visualizzato in un layout con ViewPager e che utilizza AppCompatActivity. Stavo ricevendo illegalStateException e crash quando si ruota lo schermo.

Grazie alle risposte della risposta @almisoft e @Zagorax, ho provato a chiamare notifyDataSetChanged(); giusto prima di mostrare la finestra di dialogo e il problema sembra essere andato via.

1

provare questo. Ho lavorato

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

     } 
0

Una risposta Linea basta aggiungere viewpageadapter.notifyDataSetChanded()