From eacacb5989a9ad178694dce8f59767fc9b71ea89 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Wed, 23 Mar 2016 13:07:27 -0700 Subject: Fix bugs around restoring nested retained instance fragments Framework edition In a few configurations the child fragment state of a retained-instance fragment would not be preserved correctly, leading to child fragments not being restored. Clean this up along with live state management issues that were leading to logged warnings during normal fragment operation. Bug 27371492 Bug 27477824 Change-Id: I847ac05b1757392580e008dc20c50c3ef365ca68 --- core/java/android/app/Fragment.java | 45 +++++++++++++++++------------- core/java/android/app/FragmentManager.java | 9 ++++-- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 6870bbff48c7..f7a4557f8760 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1429,16 +1429,20 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final Context context = getContext(); final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0; if (version >= Build.VERSION_CODES.N) { - if (savedInstanceState != null) { - Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG); - if (p != null) { - if (mChildFragmentManager == null) { - instantiateChildFragmentManager(); - } - mChildFragmentManager.restoreAllState(p, mChildNonConfig); - mChildNonConfig = null; - mChildFragmentManager.dispatchCreate(); + restoreChildFragmentState(savedInstanceState, true); + } + } + + void restoreChildFragmentState(@Nullable Bundle savedInstanceState, boolean provideNonConfig) { + if (savedInstanceState != null) { + Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG); + if (p != null) { + if (mChildFragmentManager == null) { + instantiateChildFragmentManager(); } + mChildFragmentManager.restoreAllState(p, provideNonConfig ? mChildNonConfig : null); + mChildNonConfig = null; + mChildFragmentManager.dispatchCreate(); } } } @@ -1692,6 +1696,18 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ 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; + } } /** @@ -2252,16 +2268,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final Context context = getContext(); final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0; if (version < Build.VERSION_CODES.N) { - if (savedInstanceState != null) { - Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG); - if (p != null) { - if (mChildFragmentManager == null) { - instantiateChildFragmentManager(); - } - mChildFragmentManager.restoreAllState(p, null); - mChildFragmentManager.dispatchCreate(); - } - } + restoreChildFragmentState(savedInstanceState, false); } } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 063194310e77..2852baf9c21b 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -941,6 +941,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (!f.mRetaining) { f.performCreate(f.mSavedFragmentState); + } else { + f.restoreChildFragmentState(f.mSavedFragmentState, true); + f.mState = Fragment.CREATED; } f.mRetaining = false; if (f.mFromLayout) { @@ -1009,6 +1012,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate f.mSavedFragmentState = null; } case Fragment.ACTIVITY_CREATED: + if (newState > Fragment.ACTIVITY_CREATED) { + f.mState = Fragment.STOPPED; + } case Fragment.STOPPED: if (newState > Fragment.STOPPED) { if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); @@ -1108,7 +1114,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (!f.mRetaining) { f.performDestroy(); } else { - f.mState = Fragment.INITIALIZING; + f.mState = Fragment.CREATED; } f.mCalled = false; @@ -1124,7 +1130,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate f.mHost = null; f.mParentFragment = null; f.mFragmentManager = null; - f.mChildFragmentManager = null; } } } -- cgit v1.2.3-59-g8ed1b