2013-02-11 74 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) { 

     } 
} 
相關問題