IllegalArgumentException: не обнаружено никакого поиска для id для фрагмента при быстром переключении вкладок ActionBar

Я разрабатываю приложение для Android для планшетов и не использую библиотеку совместимости.

Существует только одно действие, и он использует ActionBar с 3 вкладками. В TabListener я использую setContentView для загрузки макета, специфичного для этой вкладки, а затем добавляю соответствующие фрагменты к своим фреймам. Это почти работает точно так, как я хочу, за исключением случаев, когда вы переключаетесь между вкладками достаточно быстро, чтобы приложение вышло из строя.

Я использую Samsung Galaxy Tab, поскольку мое устройство для отладки и переключение вкладок происходит очень быстро. В нормальном темпе я могу переключаться между ними, и страницы загружаются мгновенно. Проблема заключается в том, когда я переключаю гиперпереключатель между вкладками.

Сначала я получил

IllegalStateException: Fragment not added 

Как показано здесь: http://code.google.com/p/android/issues/detail?id=17029 Следуя предложению использовать блоки try / catch в onTabUnselected, я сделал приложение немного более надежным, но это привело к Проблема:

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

Я не нашел другого случая в Интернете кого-то другого, имеющего такую ​​же проблему, поэтому я обеспокоен тем, что могу делать что-то, что не поддерживается. Опять же , я пытаюсь использовать 3 разных макета в одном действии. Когда вы нажимаете на вкладку, слушатель вызовет setContentView для изменения макета, а затем добавит фрагменты. Он прекрасно работает, если вы не начнете агрессивно переключаться между вкладками.

Я получил эту идею от: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.html и вместо TabListener, содержащего ссылку на один фрагмент , У меня есть массив из них. Кроме того, я не использую attach / detach, поскольку они были добавлены в API 13.

Моя теория заключается в том, что либо setContentView не закончил создание представлений, а потому FragmentTransaction не может их добавить, или фрагменты добавляются для одной вкладки при выборе другой вкладки и вызывается setContentView, уничтожая другой набор представлений.

Я попытался что-то взломать, чтобы замедлить переключение вкладок, но ничего не получилось.

Вот код моего 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"); } } } } 

И, наконец, трассировка стека:

 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) 

СПАСИБО!!

Solutions Collecting From Web of "IllegalArgumentException: не обнаружено никакого поиска для id для фрагмента при быстром переключении вкладок ActionBar"

Хорошо, нашел способ обойти это:

Поместите ссылки на фрагменты в файлах макета и окружьте вызов setContentView в onTabSelected в блоке try / catch.

Обработка исключений позаботилась об этом!

Я знаю, что это немного старый вопрос, но у меня было то же самое и найти другую работу.

Сам метод описан здесь. Избегайте воссоздания одного и того же вида при переключении табуляции

Но в контексте этого конкретного сбоя выполнение Show / Hide вместо добавления / замены позволяет избежать множества быстрых вызовов onCreateView на фрагменте.

Мой последний код оказался примерно таким:

 @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()]); } 

См. Аналогичный случай в отчете о сбое Google Play.

 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) 

Соответствующий код:

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

^^ Здесь происходит сбой

Фрагмент определенно существует (он был возвращен findFragmentById), но вызов hide () взорвался с «IllegalStateException: Fragment not added»

Не добавлено? Как это не было добавлено, если findFragmentById смог его найти?

Все вызовы FragmentManager создаются из потока пользовательского интерфейса.

Фрагмент, удаляемый (fragDisplay), был добавлен ранее, и я уверен, что его FragmentTransaction был зачислен.

Исправлена ​​ошибка, перебирая мои фрагменты, удаляя любые из них, которые были добавлены, а затем добавлены новые. Также сначала проверьте, что вы не пытаетесь заменить его нулевым или существующим фрагментом.

Изменить: похоже, это было просто

 getChildFragmentManager().executePendingTransactions(); 

Что остановило его от сбоев

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