26

ich das ViewPager Beispiel mit ActionBar Tabs aus dem Android Dokumentation here genommen werden.Illegal: Die PagerAdapter Anwendung verändert den Inhalt des Adapters ohne PagerAdapter # Aufruf notifyDataSetChanged

Leider sobald ich die addTab Methode aufrufen, die Anwendung abstürzt, mit folgender Ausnahme:

Illegal: Die PagerAdapter Anwendung verändert den Inhalt des Adapter ohne PagerAdapter # notifyDataSetChanged ruft! Erwartete Adapter Elementanzahl 0, gefunden 1.

Dies ist der 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) { 
     } 
    } 
} 

Ich erhalte kein Adapter in einem anderen Teil meines Codes ändern und ich rufe die addTab Methode aus dem Haupt-Thread, endet die addTab Methode mit einem Aufruf an notifyDataSetChanged. Wie in der Dokumentation empfohlen:

PagerAdapter unterstützt Datensatzänderungen. Datensatzänderungen müssen unter dem Hauptthread erfolgen und müssen mit einem Aufruf von notifyDataSetChanged() ähnlich den von BaseAdapter abgeleiteten AdapterView-Adaptern enden.

Antwort

18

Ich hatte eine harte Zeit, meine ViewPager arbeiten zu lassen. Am Ende scheint das Beispiel in der Dokumentation falsch zu sein.

Die addTab Methode sollte wie folgt sein:

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

Beachten Sie die Reihenfolge der letzten drei Operationen. Im ursprünglichen Beispiel wurde notifyDataSetChanged nach der mActionBar.addTab Funktion aufgerufen.

Sobald Sie die addTab auf der ActionBar anrufen, wird automatisch die erste Registerkarte, die Sie hinzufügen, automatisch ausgewählt. Aus diesem Grund wird das onTabSelected -Ereignis ausgelöst und beim Versuch, die Seite abzurufen, zeigt es die IllegalStateException, weil es eine Diskrepanz zwischen der erwarteten Elementanzahl und dem tatsächlichen Element feststellt.

+0

Ich habe für diese eine Weile suchen. Bin ich der Einzige, der es seltsam findet, dass der Fehler so aussieht, als würde ich notifyDataSetChanged() nicht aufrufen, wenn ich wirklich nur die Aktion (setCurrentItem in meinem Fall) nach NotifyDataSetChanged() ausführen muss? – wizurd

8

Ich reparierte sie durch callinig notifyDataSetChanged() einmal und kurz vor dem nächsten Aufruf von 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

Gute Sachen hier ... Danke! – worked

0

ich in FragmentStatePager Adapter das gleiche Problem hatte. in onResume() Bei der Neuinitialisierung des Adapters und ViewPager wird der gleiche Fehler IllegalStateException angezeigt. Die Lösung:

Wenn Sie die Registerkarte addtab hinzufügen, wählen Sie die Registerkarte, die nicht ausgewählt werden soll, indem Sie setSelected params auf false festlegen.

actionBar.addTab(tab,false); 

ich glaube, die Ausnahme erschien wegen Überschreiben der onTabSelected() Methode, wie die folgenden

viewPager.setCurrentItem(tab.getPosition()); 

Als addTab() nannte es nicht zu erkennen, welche viewPager und Adapter, um die Registerkarte hinzuzufügen.

3

Ich war immer diesen Fehler, wie Sie durch die Registerkarten innerhalb getCount Referenzierung():

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

Wenn diese instanziiert sollte entweder als separate Variable übergeben, oder der Pager sollte nach eingerichtet werden Die Sammlung wurde bevölkert/mutiert.

0

Mein Problem war nicht genau das gleiche, aber ähnlicher Kontext.

Ich habe einen AlertDialog in einem Layout angezeigt, das ViewPager hat und AppCompatActivity verwendet. Ich bekam die IllegalStateException und stürzte beim Drehen des Bildschirms ab.

Danke an die Antworten von @almisoft und @Zagorax, ich habe versucht, notifyDataSetChanged(); direkt aufzurufen, bevor ich den Dialog zeige, und das Problem scheint weggegangen zu sein.

1

versuchen Sie dies. Ich arbeitete

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

One Line Antwort nur viewpageadapter.notifyDataSetChanded add()

Verwandte Themen