IllegalArgumentException:当快速切换ActionBar选项卡时,没有findid为fragment的视图

我正在开发平板电脑的Android应用程序,而不是使用兼容性库。

只有一个活动,它使用带有3个选项卡的ActionBar。 在TabListener中,我使用setContentView加载特定于该选项卡的布局,然后将相关片段添加到其框架中。 这几乎和我想要的完全一样,只是当你在标签之间切换的速度足够快的时候,应用程序就会崩溃。

我正在使用三星Galaxy Tab作为我的debugging设备,切换选项卡非常快。 以正常速度,我可以在它们之间来回切换,并且页面立即被加载。 问题是当我超级切换标签之间。

起初,我得到了一个

IllegalStateException: Fragment not added 

如下所示: http : //code.google.com/p/android/issues/detail? id=17029按照在onTabUnselected中使用try / catch块的build议,我使得应用程序更强大一点,但是这导致手头的问题:

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

我还没有发现任何其他人遇到同样的问题,所以我担心我可能会做一些不被支持的事情。 再一次 ,我想要做的是在一个Activity中使用3个不同的布局 – 当你点击一个选项卡时,监听器将调用setContentView来更改布局,然后添加片段。 除非您开始积极地在标签之间切换,否则它的效果非常好。

我有这样的想法: http : //developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.html而不是TabListener保持一个片段的引用,我有他们的一个arrays。 此外,我不使用附加/分离,因为这些只是添加在API 13。

我的理论是,setContentView还没有完成创build视图,这就是为什么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:当快速切换ActionBar选项卡时,没有findid为fragment的视图"

好的,find一个解决办法:

将引用放到布局文件中,并在try / catch块中将onTabSelected中的setContentView调用包围起来。

exception处理照顾它!

我知道这是一个稍微老的问题,但我也有同样的,find一个不同的工作。

这里描述的方法本身避免在执行制表符切换时重新创build相同的视图

但在这个特定的崩溃的上下文中,做显示/隐藏而不是添加/replace可以避免多次快速调用片段上的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:未添加片段”

没有添加? 如果findFragmentById能够find它,它怎么不被添加?

所有FragmentManager调用都是从UI线程进行的。

被删除的片段(fragDisplay)被添加了,我确信它的FragmentTransaction被提交。

修复它通过循环我的片段,删除已添加的任何,然后添加新的。 另外首先检查你是不是试图用空或者现有的片段replace它。

编辑:看起来像只是

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