2013-02-11 45 views
8

上下文:我有ActivityFragment和3 InnerFragments。当调用FragmentonDestroy()时,我想从FragmentManager中删除内部片段。下面的代码来自onDestroy()FragmentManager NullPointerException当试图commitAllowingStateLoss

问题:FragmentManager抛出NullPointerException,大概当commitAllowingStateLoss()被调用。我不明白为什么。

@Override 
public void onDestroy() 
{ 
    super.onDestroy(); 
    if (getFragmentManager().findFragmentById(R.id.fragment_framelayout_left) != null) 
    { 
     FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
     fragmentTransaction.remove(mLeftFragment); 
     fragmentTransaction.commitAllowingStateLoss(); 
    } 
} 

堆栈跟踪:

02-11 12:15:14.162: E/AndroidRuntime(25911): FATAL EXCEPTION: main 
02-11 12:15:14.162: E/AndroidRuntime(25911): java.lang.NullPointerException 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1419) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.handleCallback(Handler.java:725) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.dispatchMessage(Handler.java:92) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Looper.loop(Looper.java:137) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.app.ActivityThread.main(ActivityThread.java:5039) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invokeNative(Native Method) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invoke(Method.java:511) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at dalvik.system.NativeStart.main(Native Method) 
+1

我不会完全按照你的架构。 'InnerFragments'是否存在于'Fragment'中?如果是这样,我认为你应该有'getChildFragmentManager()'管理它们(而不是'''''FragmentManager')。这样,当“碎片”破坏时,其子节点“InnerFragments”也会被破坏,而无需额外的代码。 – 2013-02-12 04:14:30

+0

是的,内碎片住在碎片内(至少在平板电脑上)。在手机上,他们生活在一个Activity内(Activity1内的InnerFragment1,Activity2内的InnerFragment2)。这就是我使用该代码的原因。它也可以在Activities中使用getChildFragmentManager()吗? LE:愚蠢的问题,对不起。我会在几个小时内尝试一下你的想法,看看它是如何发展的。 – 2013-02-12 12:44:02

+1

'getChildFragmentManager()'只在'Fragments'中,因为'Activities'不能访问子'FragmentManagers'。然而,'Fragments'可以调用'getFragmentManager()'并访问其父'Activity'的'FragmentManager',允许他们在自己的顶部启动新的'Fragments',而不需要他们的父'Activity'来为他们做。 – 2013-02-12 14:23:51

回答

9

FragmentManager管理所有FragmentsActivity水平,它们的生命周期将被捆绑到母Activity。子女Fragment经理管理所有FragmentsFragment级别,其生命周期将与该父母Fragment绑定。

因此对于您的手机架构,请使用getFragmentManager()将您的InnerFragment添加到您的Activity中。当Activity销毁好(通过后退按钮/ finish())时,FragmentManager将销毁并释放InnerFragment

对于您的平板电脑架构,请使用getChildFragmentManager()(在最新的支持库中)将InnerFragments添加到Fragment。当Fragment销毁好时,FragmentManager会销毁并释放InnerFragments

您不应该自己管理释放和销毁您的Fragments。我建议记录您的ActivitiesFragments的生命周期事件,以便您可以观察它们是否经历其状态并确保正确的行为。

+0

太棒了。非常感谢。这解决了它。一个小问题。如果我使用ChildFragmentManager,我不能在子Fragments上设置RetainInstance(true)。有没有解决方法?或者为什么它应该像这样? – 2013-02-13 09:37:16

+1

使用'setRetainInstance(true)'实际上已经是一种解决方法。 Google建议的方法是在'onSaveInstanceState()'中保存任何变量状态,并在'onCreate'和'onCreateView'中恢复。在任何时候,操作系统可能会在内存不足的情况下运行,并且需要销毁你的'Fragments'和/或'Activities',所以他们有责任保存它们当前的状态,并且恢复这个状态以显示给用户因为他们回来时没有什么变化。以下是Google建议您保存状态的方式http://developer.android.com/training/basics/activity-lifecycle/recreating.html。 – 2013-02-13 14:09:29

+1

这里有一些关于'setRetainInstance(true)的更多信息 - http://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean – 2013-02-13 14:10:40

1

该NullPointerException异常是由一个事实,即活动的处理程序是从FragmentManager未设置引起的,所以一个“解决方案”,将防止死机如下:

public void onDestroy(){ 
     super.onDestroy(); 
     try { 
      Field mActivityField = getFragmentManager().getClass().getDeclaredField("mActivity"); 
      mActivityField.setAccessible(true); 
      mActivityField.set(getFragmentManager(), this); 

      Field mPendingActionsField = getFragmentManager().getClass().getDeclaredField("mPendingActions"); 
      mPendingActionsField.setAccessible(true); 
      mPendingActionsField.set(getFragmentManager(), null); 


      Field f = Activity.class.getDeclaredField("mHandler"); 
      f.setAccessible(true); 
      Handler handler = (Handler) f.get(this); 
      handler.close(); 
     } catch (Throwable e) { 

     } 
} 
相关问题