导致一个java.IllegalStateException错误,没有活动,只有在第二次导航到分片时

我遇到一个非常令人费解的错误,我不知道如何开始工作。

我有一个简单的应用程序与一个活动,意见是用碎片实施。 其中一个片段里面有一个ViewPager; 所以我决定,我想使用v4支持库的getChildFragmentManager类。 我也不得不使用ActionBarSherlock,这导致了一个问题,因为它不附带v4库的v11。

我通过用v11库replaceABS中的v4支持库来解决这个问题,并且所有已编译和似乎都可以正常工作的工具,包括ViewPager。

这是奇怪的部分:

第一次用ViewPager打开片段时,它正常工作; 但第二次被导航到,应用程序崩溃,给一个无用的堆栈跟踪。 从debugging中,我发现问题是由getChildFragmentManager返回的FragmentManager; 它会抛出No Activity错误。

有谁知道可能是什么原因造成的?

我会发布你认为相关的代码。

谢谢大卫

我跟着jeremyvillalobos的回答 (这是非常有用的),导致我这个解决方法 。

public class CustomFragment extends Fragment { private static final Field sChildFragmentManagerField; static { Field f = null; try { f = Fragment.class.getDeclaredField("mChildFragmentManager"); f.setAccessible(true); } catch (NoSuchFieldException e) { Log.e(LOGTAG, "Error getting mChildFragmentManager field", e); } sChildFragmentManagerField = f; } @Override public void onDetach() { super.onDetach(); if (sChildFragmentManagerField != null) { try { sChildFragmentManagerField.set(this, null); } catch (Exception e) { Log.e(LOGTAG, "Error setting mChildFragmentManager field", e); } } } ... } 

它适用于我,无需重新实例化片段。

这似乎是一个错误报告在

https://code.google.com/p/android/issues/detail?id=42601

variables

FragmentManagerImpl mChildFragmentManager;

在Fragment.java没有设置为null分离。 所以下一次加载片段时,variables仍然指向最后一个父亲。

正如在该线程中所讨论的,解决方法是重新实例化片段。

在我的情况下,我在ActionBar选项卡中切换片段。 困扰的Fragment已经嵌套了Fragments,并在回到文件加载器Fragment时崩溃了应用程序。 所以这是解决方法:

 class MainTabsListener implements ActionBar.TabListener { public Fragment fragment; public int TabPosition; public MainTabsListener(Fragment fragment, int tab_position) { this.fragment = fragment; TabPosition = tab_position; } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { CurrentFragment = fragment; CurrentTabSelectedPos = TabPosition; /** * This is a work-around for Issue 42601 * https://code.google.com/p/android/issues/detail?id=42601 * * The method getChildFragmentManager() does not clear up * when the Fragment is detached. */ if( fragment instanceof FileLoaderFragment ){ fragment = reinstatiateFileLoaderFragment(); } ft.replace(R.id.fragment_container, fragment); } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { ft.remove(fragment); } } 

可能你的错误是android.view.InflateException?

如果是这样,你应该dynamic地膨胀Fragment,不要使用XML布局。

而且,您不应将定义XML Layout的片段定位到片段事务。

我也有同样的问题。

在一个活动中,我有3 bouttons切换与transaction.replace片段(…)

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.layout_tablet_paneau, mLigneMessageFragment);

其中一个片段包含一个带有自定义FragmentPagerAdapter的ViewPage。 因此,我必须做getChildFragmentManager(),以嵌套片段。

构造函数在这里:

 public LignePagerAdapter(Fragment ligneMessageTabletFragment) { super(ligneMessageTabletFragment.getChildFragmentManager()); } 

所以我有同样的错误:这个片段第一次显示,但是当我显示其他片段,并回到这一个,我得到这个exception:

 02-26 11:57:50.798:D / ACRA(776):等待Toast +工人结束。 杀死应用程序? 真正
 02-26 11:57:50.798:E / AndroidRuntime(776):致命的例外:主
 02-26 11:57:50.798:E / AndroidRuntime(776):java.lang.IllegalStateException:没有活动
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1075)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1861)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1474)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:931)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.support.v4.app.FragmentManagerImpl $ 1.run(FragmentManager.java:429)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.os.Handler.handleCallback(Handler.java:587)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.os.Handler.dispatchMessage(Handler.java:92)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.os.Looper.loop(Looper.java:132)
 02-26 11:57:50.798:E / AndroidRuntime(776):在android.app.ActivityThread.main(ActivityThread.java:4126)
 02-26 11:57:50.798:E / AndroidRuntime(776):在java.lang.reflect.Method.invokeNative(Native Method)
 02-26 11:57:50.798:E / AndroidRuntime(776):在java.lang.reflect.Method.invoke(Method.java:491)
 02-26 11:57:50.798:E / AndroidRuntime(776):at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:844)
 02-26 11:57:50.798:E / AndroidRuntime(776):at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
 02-26 11:57:50.798:E / AndroidRuntime(776):在dalvik.system.NativeStart.main(本机方法)
 02-26 11:57:52.818:I / dalvikvm(776):threadid = 4:对信号3做出反应
 02-26 11:57:52.818:I / dalvikvm(776):将堆栈跟踪写入“/data/anr/traces.txt”

所以,而不是把同一个片段的实例,我可以重新创build这个,所以它解决了这个问题,但我似乎没有效率。

 transaction.replace(R.id.layout_tablet_paneau, LigneMessageTabletFragment.newInstance()); 

可悲的是,这是一个支持v4的bug,仍然存在:(

当您通过Navigation Drawer或其他类似的东西select其他片段时,将会分离出具有子片段的片段。 所以这些子片段的fragmentManager(getChildFragmentManager())不再存在。 而那些碎片返回,发生错误。 炸弹!

显然,支持v4应该在onDetach()中清理mChildFragmentManager,但是没有,所以我们必须依靠自己。 例如在具有子片段的片段中的以下代码:

 @Override public void onDetach() { try { Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager"); childFragmentManager.setAccessible(true); childFragmentManager.set(this, null); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } super.onDetach(); } 

一切都会好的,祝你有美好的一天:)

请参阅@lopisan回答:

我长期使用他的解决scheme。

但我找出有更好的方法来做到这一点!

如果mChildFragmentManager.mActivity为null,则将mChildFragmentManager设置为null。 当performActivityCreated方法。

 @Override void performActivityCreated(Bundle savedInstanceState) { if (getFragmentManagerActivity(mChildFragmentManager) == null) { setChildFragmentManager(this, null); } super.performActivityCreated(savedInstanceState); } public static FragmentActivity getFragmentManagerActivity(FragmentManager fragmentManager) { FragmentManagerImpl fm = (FragmentManagerImpl) fragmentManager; return fm.mActivity; } private static final Field sChildFragmentManagerField; static { /** * BUG : causing a java.IllegalStateException error, No Activity, only * when navigating to Fragment for the SECOND time * http://stackoverflow.com /questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed * http://stackoverflow.com/questions/14929907/causing-a-java-illegalstateexception-error-no-activity-only-when-navigating-to */ Field f = null; try { f = Fragment.class.getDeclaredField("mChildFragmentManager"); f.setAccessible(true); } catch (NoSuchFieldException e) { Log.e(TAG, "Error getting mChildFragmentManager field", e); } sChildFragmentManagerField = f; } public static void setChildFragmentManager(Fragment fragment, FragmentManager fragmentManager) { if (sChildFragmentManagerField != null) { try { sChildFragmentManagerField.set(fragment, fragmentManager); } catch (Exception e) { Log.e(TAG, "Error setting mChildFragmentManager field", e); } } } 

我坚持使用BottomNavigationView切换和导致应用程序崩溃的片段replace相同的错误。 正常的速度,它工作得很好,如果用户做快速切换它曾经崩溃说

IllegalStateException没有活动

在日志中

在我之前

 fragmentA = new FragmentA(); fragmentB = new FragmentB(); fragmentC = new FragmentC(); mBottomNavigationView.setOnNavigationItemSelectedListener(item -> { switch (item.getItemId()) { case R.id.fragmentA: replaceFragment(fragmentA); case R.id.fragmentB: repalceFragment(fragmentB); case R.id.fragmentC: repalceFragment(fragmentC); } }; 

我认为这个片段的预先创build和使用他们是为了replace正在创造的问题,现在我使它重新创build每一次。 它开始工作正常

 mBottomNavigationView.setOnNavigationItemSelectedListener(item -> { switch (item.getItemId()) { case R.id.fragmentA: fragment = new FragmentA(); replaceFragment(fragment); case R.id.fragmentB: fragment = new FragmentB(); repalceFragment(fragment); case R.id.fragmentC: fragment = new FragmentC(); repalceFragment(fragment); } }; public void repalceFragment(Fragment fragment) { if (!this.isFinishing()) { if (!fragment.isAdded()) { if (!this.mDisplayedFragment.isRemoving()) { getFragmentManager().beginTransaction().replace(R.id.layout_fragment_container, fragment).commit(); this.mDisplayedFragment = fragment; } } } } 

希望对一些人有所帮助,我做了太多的防守编码,但它解决了我快速切换片段的问题

请检查这个链接的第32号:

分离父代片段后保留子片段pipe理器

脚步:

  1. 下载并复制这个类到你的项目
  2. 使用支持v4的一个扩展每个片段(最佳实践)
  3. 使用该类而不是FragmentStatePagerAdapter