2011-09-28 6 views
8

Pracuję nad aplikacją dla systemu Android na tablety i nie przy użyciu biblioteki zgodności.IllegalArgumentException: Brak widoku dla id dla fragmentu, gdy szybkie przełączanie ActionBar Tabs

Jest tylko jedna czynność i korzysta z paska akcji z 3 zakładkami. W TabListener Używam setContentView do załadowania układu określonego dla tej karty, a następnie dodania odpowiednich fragmentów do ich ramek. Ta wersja prawie działa dokładnie tak, jak chcę, z wyjątkiem sytuacji, gdy przełączasz się między kartami wystarczająco szybko, aby aplikacja się zawiesiła.

Używam karty Samsung Galaxy jako mojego urządzenia do debugowania, a przełączanie kart jest naprawdę szybkie. W normalnym tempie mogę przełączać się między nimi i strony są ładowane natychmiast. Problem polega na tym, że przełączam się między kartami.

Początkowo dostałem

IllegalStateException: Fragment not added 

jak widać tutaj: http://code.google.com/p/android/issues/detail?id=17029 zgodnie z sugestią użyć spróbuj/bloków catch w onTabUnselected, zrobiłem aplikację trochę bardziej wydajny, ale to prowadzić do emisji pod ręką:

IllegalArgumentException: No view found for id 0x... for fragment ... 

nie znalazłem żadnej innej sprawy w internecie kogokolwiek innego mający ten sam problem, więc obawiam się, że mogę robić coś, co nie jest obsługiwana. Ponownie, staram się użyć 3 różnych układów w jednym działaniu - po kliknięciu na kartę słuchacz wywoła funkcję setContentView, aby zmienić układ, a następnie doda fragmenty. Działa to pięknie, chyba że zaczniesz agresywnie przełączać się między kartami.

Pomysł na to pochodzi z: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.html i zamiast TabListener z odniesieniem do jednego fragmentu, mam ich tablicę. Ponadto, nie używam attach/detach, ponieważ zostały one dodane w API 13.

Moja teoria mówi, że albo setContentView nie zakończył tworzenia widoków, i dlatego FragmentTransaction nie może ich dodać, LUB fragmenty są dodawana do jednej karty po wybraniu innej karty i wywołaniu setContentView, niszcząc inny zestaw widoków.

Próbowałem zhakować coś, aby spowolnić przełączanie kart, ale nigdzie się nie dostałem.

Oto kod dla mojego TabListener:

private class BTabListener<T extends Fragment> implements ActionBar.TabListener{ 

    private int mLayout; 
    private Fragment[] mFrags; 
    private TabData mTabData; 
    private Activity mAct; 
    private boolean mNoNewFrags; 


    public BTabListener(Activity act, int layout, TabData td, boolean frags){ 
     mLayout = layout; 
     mTabData = td; 
     mAct = act; 
     mNoNewFrags = frags; 

     mFrags = new Fragment[mTabData.fragTags.length]; 
     for(int i=0; i<mFrags.length; i++){ 
      //on an orientation change, this will find the fragments that were recreated by the system 
      mFrags[i] = mAct.getFragmentManager().findFragmentByTag(mTabData.fragTags[i]); 
     } 

    } 

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

    } 

    @Override 
    public void onTabSelected(Tab tab, FragmentTransaction ft) { 
     //this gets called _after_ unselected 
     //note: unselected wont have been called after an orientation change! 
     //we also need to watch out because tab 0 always gets selected when adding the tabs 

     //set the view for this tab 
     mAct.setContentView(mLayout); 

     for(int i=0; i<mFrags.length; i++){ 
      //this will be null when the tab is first selected 
      if(mFrags[i]==null){ 
       mFrags[i] = Fragment.instantiate(GUITablet.this, mTabData.classes[i].getName());      
      } 

      //if there was an orientation change when we were on this page, the fragment is already added 
      if(!mNoNewFrags || mDefaultTab!=tab.getPosition()){ 
       ft.add(mTabData.containterIDs[i], mFrags[i], mTabData.fragTags[i]); 
      } 
     } 
     mNoNewFrags = false; 


    } 

    @Override 
    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
     // this gets called when another tab is selected, before it's onSelected method 

     for(Fragment f : mFrags){ 
      try{ //extra safety measure 
       ft.remove(f); 
      }catch(Exception e){ 
       e.printStackTrace(); 
       System.out.println("unselect couldnt remove"); 
      } 
     } 
    } 

} 

I wreszcie, ślad stosu:

09-29 01:53:08.200: ERROR/AndroidRuntime(4611): java.lang.IllegalArgumentException: No view found for id 0x7f0b0078 for fragment Fraggle{40ab2230 #2 id=0x7f0b0078 dummy2} 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:729) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:926) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.BackStackRecord.run(BackStackRecord.java:578) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1226) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.FragmentManagerImpl$1.run(FragmentManager.java:374) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.os.Handler.handleCallback(Handler.java:587) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.os.Handler.dispatchMessage(Handler.java:92) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.os.Looper.loop(Looper.java:132) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at android.app.ActivityThread.main(ActivityThread.java:4028) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at java.lang.reflect.Method.invokeNative(Native Method) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at java.lang.reflect.Method.invoke(Method.java:491) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
09-29 01:53:08.200: ERROR/AndroidRuntime(4611):  at dalvik.system.NativeStart.main(Native Method) 

DZIĘKUJĘ !!

+0

może ktoś Pomóż mi pozbyć się tego błędu .... [link] [1] [1]: http://stackoverflow.com/questions/2540 0641/fragmentmanager-illegalargumentexception-no-view-found-for-id-for-fragment? Noredirect = 1 –

+0

@SamKazmi, czy wypróbowałeś sugerowane odpowiedzi ...? – hooby3dfx

Odpowiedz

5

Dobra, znalazłem sposób wokół to:

umieścić odniesienia do fragmentów w plikach układ, w otoczeniu połączenia setContentView w onTabSelected w bloku try/catch.

Zajęło się tym obsługa wyjątków!

+0

Czy nie kończysz z pustym ekranem? – CACuzcatlan

+0

Dlaczego miałbym mieć pusty ekran? Myślę, że błędy wystąpiły tylko wtedy, gdy szybkie przełączanie zostało wyłączone lub zaznaczone PODCZAS innego wybrania, więc ostateczny wybór zawsze działa (bez wyjątków). – hooby3dfx

1

Wiem, że to trochę stare pytanie, ale miałem to samo i znajdowałem inną pracę.

Sama metoda opisana jest tutaj Avoid recreating same view when perform tab switching

ale w kontekście tego konkretnego wypadku, robi pokazać/ukryć zamiast dodatku/wymienić unika wielu szybkich połączeń do onCreateView na fragmencie.

Moja ostatnia kod skończyło się coś takiego:

@Override 
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 
if (fragments[tab.getPosition()] == null) { 
    switch(tag.getPosition()){ 
     case 0: fragments[tab.getPosition()] = new // fragment for this position 
     break; 
     // repeat for all the tabs, for each `case` 
    } 
    fragmentTransaction.add(R.id.container, fragments[tab.getPosition()]); 
}else{ 
    fragmentTransaction.show(fragments[tab.getPosition()]); 
} 
} 

@Override 
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 
if (fragments[tab.getPosition()] != null) 
    fragmentTransaction.hide(fragments[tab.getPosition()]); 
} 
0

Widząc podobny przypadek w Google Play raportu katastrofy.

java.lang.IllegalStateException: 
    Fragment not added: MessageDisplayFragment{406e28f0 #2 id=0x7f0b0020} 
at android.app.BackStackRecord.hide(BackStackRecord.java:397) 
at org.kman.AquaMail.ui.AccountListActivity$UIMediator_API11_TwoPane. 
    closeMessageDisplay(AccountListActivity.java:2585) 

odpowiedni kod:

AbsMessageFragment fragDisplay = (AbsMessageFragment) 
    mFM.findFragmentById(R.id.fragment_id_message_display); 

if (fragDisplay != null) { 
    FragmentTransaction ft = mFM.beginTransaction(); 
    ft.setTransition(FragmentTransaction.TRANSIT_NONE); 
    ft.show(some other fragment); 
    ft.hide(fragDisplay); 

^^ To jest, gdy się zawiesi

Fragment jest tam zdecydowanie (został zwrócony przez findFragmentById), ale wzywając hide() wysadzili z "IllegalStateException: fragment nie został dodany"

Nie dodano? Jak go nie dodać, jeśli findFragmentById był w stanie go znaleźć?

Wszystkie wywołania FragmentManager są tworzone z wątku interfejsu użytkownika.

Fragment, który został usunięty (fragDisplay) został dodany wcześniej i jestem pewien, że jego FragmentTransaction został zatwierdzony.

0

Naprawiono go, przechodząc przez moje fragmenty, usuwając wszystkie dodane, a następnie dodając nowe. Sprawdź również najpierw, czy nie próbujesz zastąpić go wartością null lub istniejącym fragmentem.

Edit: wygląda jakby był po prostu

getChildFragmentManager().executePendingTransactions(); 

że zatrzymał go od awarii

private void replaceCurrentTabFragment(TabFragment tabFragment){ 

    if (tabFragment == null){ return; } 

    if (tabFragment == getActiveTabFragment()){ return; } 

    FragmentTransaction ft = getChildFragmentManager().beginTransaction(); 

    for (TabFragment fragment : mTabButtons.values()){ 
     if (((Fragment)fragment).isAdded()){ 
      ft.remove((Fragment)fragment); 
     } 
    } 

    ft.add(R.id.fragment_frameLayout, (Fragment) tabFragment); 
    ft.commit(); 
    getChildFragmentManager().executePendingTransactions(); 

} 

private TabFragment getActiveTabFragment(){ 
    return (TabFragment) getChildFragmentManager().findFragmentById(R.id.fragment_frameLayout); 
} 
Powiązane problemy