OSDN Git Service

Move child FragmentManager shutdown for retained fragments
authorAdam Powell <adamp@google.com>
Thu, 21 Apr 2016 18:04:41 +0000 (11:04 -0700)
committerAdam Powell <adamp@google.com>
Thu, 21 Apr 2016 18:04:41 +0000 (11:04 -0700)
Some apps out there do some creative things in terms of calling their
own onDetach methods from elsewhere. Perform the child FragmentManager
shutdown for retained fragments in a package-level perform method
instead of in onDetach itself.

Also mark all existing fragment methods with @CallSuper.

Bug 28293847

Change-Id: I343b610f8d427fe5cabd523a78fbf0e6f3b34c57

core/java/android/app/Fragment.java
core/java/android/app/FragmentManager.java

index a221c98..f4fe1eb 100644 (file)
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.animation.Animator;
+import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
@@ -1335,6 +1336,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
      */
     @Deprecated
+    @CallSuper
     public void onInflate(AttributeSet attrs, Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1381,6 +1383,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
         onInflate(attrs, savedInstanceState);
         mCalled = true;
@@ -1421,6 +1424,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
      */
     @Deprecated
+    @CallSuper
     public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1429,6 +1433,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * Called when a fragment is first attached to its context.
      * {@link #onCreate(Bundle)} will be called after this.
      */
+    @CallSuper
     public void onAttach(Context context) {
         mCalled = true;
         final Activity hostActivity = mHost == null ? null : mHost.getActivity();
@@ -1442,6 +1447,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @deprecated Use {@link #onAttach(Context)} instead.
      */
     @Deprecated
+    @CallSuper
     public void onAttach(Activity activity) {
         mCalled = true;
     }
@@ -1473,6 +1479,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onCreate(@Nullable Bundle savedInstanceState) {
         mCalled = true;
         final Context context = getContext();
@@ -1558,6 +1565,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1573,6 +1581,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onViewStateRestored(Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1582,6 +1591,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * tied to {@link Activity#onStart() Activity.onStart} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onStart() {
         mCalled = true;
 
@@ -1603,6 +1613,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * tied to {@link Activity#onResume() Activity.onResume} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onResume() {
         mCalled = true;
     }
@@ -1648,6 +1659,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
     public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
     }
 
+    @CallSuper
     public void onConfigurationChanged(Configuration newConfig) {
         mCalled = true;
     }
@@ -1657,6 +1669,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * tied to {@link Activity#onPause() Activity.onPause} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onPause() {
         mCalled = true;
     }
@@ -1666,14 +1679,17 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * tied to {@link Activity#onStop() Activity.onStop} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onStop() {
         mCalled = true;
     }
 
+    @CallSuper
     public void onLowMemory() {
         mCalled = true;
     }
 
+    @CallSuper
     public void onTrimMemory(int level) {
         mCalled = true;
     }
@@ -1687,6 +1703,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * non-null view.  Internally it is called after the view's state has
      * been saved but before it has been removed from its parent.
      */
+    @CallSuper
     public void onDestroyView() {
         mCalled = true;
     }
@@ -1695,6 +1712,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * Called when the fragment is no longer in use.  This is called
      * after {@link #onStop()} and before {@link #onDetach()}.
      */
+    @CallSuper
     public void onDestroy() {
         mCalled = true;
         //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
@@ -1743,20 +1761,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
      * Activity re-creation (see {@link #setRetainInstance(boolean)}), in which case it is called
      * after {@link #onStop()}.
      */
+    @CallSuper
     public void onDetach() {
         mCalled = true;
-
-        // Destroy the child FragmentManager if we still have it here.
-        // We won't unless we're retaining our instance and if we do,
-        // our child FragmentManager instance state will have already been saved.
-        if (mChildFragmentManager != null) {
-            if (!mRetaining) {
-                throw new IllegalStateException("Child FragmentManager of " + this + " was not "
-                        + " destroyed and this fragment is not retaining instance");
-            }
-            mChildFragmentManager.dispatchDestroy();
-            mChildFragmentManager = null;
-        }
     }
 
     /**
@@ -2568,6 +2575,27 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
         mChildFragmentManager = null;
     }
 
+    void performDetach() {
+        mCalled = false;
+        onDetach();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onDetach()");
+        }
+
+        // Destroy the child FragmentManager if we still have it here.
+        // We won't unless we're retaining our instance and if we do,
+        // our child FragmentManager instance state will have already been saved.
+        if (mChildFragmentManager != null) {
+            if (!mRetaining) {
+                throw new IllegalStateException("Child FragmentManager of " + this + " was not "
+                        + " destroyed and this fragment is not retaining instance");
+            }
+            mChildFragmentManager.dispatchDestroy();
+            mChildFragmentManager = null;
+        }
+    }
+
     private static Transition loadTransition(Context context, TypedArray typedArray,
             Transition currentValue, Transition defaultValue, int id) {
         if (currentValue != defaultValue) {
index b1dda7f..d795385 100644 (file)
@@ -1117,12 +1117,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
                                 f.mState = Fragment.INITIALIZING;
                             }
 
-                            f.mCalled = false;
-                            f.onDetach();
-                            if (!f.mCalled) {
-                                throw new SuperNotCalledException("Fragment " + f
-                                        + " did not call through to super.onDetach()");
-                            }
+                            f.performDetach();
                             if (!keepActive) {
                                 if (!f.mRetaining) {
                                     makeInactive(f);