2013-02-11 19 views
8

Kontext commitAllowingStateLoss versuchen: Ich habe eine Activity mit einem Fragment und 3 InnerFragments. Wenn die FragmentonDestroy() aufgerufen wird, möchte ich die inneren Fragmente aus der FragmentManager entfernen. Der Code von onDestroy() ist unten.FragmentManager Nullpointer wenn

Problem:FragmentManager wirft NullPointerException, wahrscheinlich, wenn commitAllowingStateLoss() genannt wird. Ich verstehe nicht warum.

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

Stapelüberwachung:

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

Ich bin nicht ganz nach Ihrer Architektur. Leben die 'InnerFragments' im' Fragment'? Wenn dem so ist, würde ich denken, dass Sie 'getChildFragmentManager()' haben sollten, um sie zu verwalten (nicht den 'FragmentManager' von' Activity'). Auf diese Weise, wenn das 'Fragment' zerstört, werden auch seine 'InnerFragments'-Kinder ohne diesen zusätzlichen Code zerstört. –

+0

Ja, die Inneren Fragmente leben innerhalb des Fragments (zumindest auf Tablets). Auf Telefonen leben sie in einer Aktivität (InnerFragment1 in Activity1, InnerFragment2 in Activity2). Deshalb habe ich diesen Code benutzt. Würde es auch mit getChildFragmentManager() in Activities funktionieren? LE: Dumme Frage, tut mir leid. Ich werde deine Idee in ein paar Stunden versuchen und sehen, wie es geht. –

+1

'getChildFragmentManager()' ist nur in 'Fragments', da 'Aktivitäten' nicht auf Children' FragmentManagers' zugreifen kann. "Fragmente" können jedoch 'getFragmentManager()' aufrufen und auf den ParentManager 'ParentManager' ihrer übergeordneten 'Activity' zugreifen, so dass sie neue' Fragments 'auf sich selbst starten können, ohne ihre übergeordnete 'Activity' zu benötigen. –

Antwort

9

Die FragmentManager verwaltet alle Fragments am Activity Ebene, und ihre Lebensdauer wird an diesem Elternteil Activity gebunden werden. Das Kind Fragment Manager verwaltet alle Fragments auf der Ebene Fragment, und ihr Lebenszyklus wird an das übergeordnete Fragment gebunden sein.

Fügen Sie also für Ihre Telefonarchitektur InnerFragment zu Ihrer Activity mit getFragmentManager() hinzu. Wenn die Activity für immer zerstört (über die Zurück-Taste/finish()), wird die FragmentManager zerstören und die InnerFragment für Sie freigeben.

Für Ihre Tablet-Architektur, fügen Sie Ihre InnerFragments zu Ihrem Fragment mit getChildFragmentManager() (in der neuesten Support-Bibliothek). Wenn die Fragment für immer zerstört, wird die FragmentManager zerstören und die InnerFragments für Sie freigeben.

Sie sollten Ihre Fragments selbst nicht befreien und zerstören müssen. Ich würde empfehlen, die Lebenszyklusereignisse Ihrer Activities und zu protokollieren, so dass Sie sehen können, wie sie ihren Status durchlaufen und korrektes Verhalten sicherstellen.

+0

Super. Danke vielmals. Das hat es gelöst. Ein kleines Problem.Wenn ich ChildFragmentManager verwende, kann ich RetainInstance (true) für die untergeordneten Fragmente nicht festlegen. Gibt es eine Problemumgehung? Oder warum sollte es sich so verhalten? –

+1

Die Verwendung von 'setRetainInstance (true)' ist eigentlich bereits ein Workaround. Der von Google vorgeschlagene Ansatz besteht darin, jeden Variablenstatus in 'onSaveInstanceState()' zu speichern und ihn in 'onCreate' und 'onCreateView' wiederherzustellen. Zu jeder Zeit kann das OS zu wenig Speicher haben und Sie müssen Ihre 'Fragmente' und/oder' Aktivitäten' zerstören, so dass es in ihrer Verantwortung liegt, in der Lage zu sein zu speichern, wie sie aktuell sind, und diesen Zustand dem Benutzer wiederzugeben als sich nichts geändert hat, wenn sie zurückkehren. So empfiehlt Google, dass Sie den Status http://developer.android.com/training/basics/activity-lifecycle/recreating.html speichern. –

+1

Und hier ist ein paar weitere Informationen über 'setRetainInstance (true)' - http://Stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean –

1

Die Nullpointer wird verursacht durch die Tatsache, dass die Aktivität des Handler aus dem FragmentManager nicht gesetzt ist, so dass eine „Lösung“, die den Absturz verhindern wird, ist die folgende:

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

     } 
} 
Verwandte Themen