Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eacacb59 authored by Adam Powell's avatar Adam Powell
Browse files

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
parent 6266d8c9
Loading
Loading
Loading
Loading
+26 −19
Original line number Diff line number Diff line
@@ -1429,19 +1429,23 @@ 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) {
            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, mChildNonConfig);
                mChildFragmentManager.restoreAllState(p, provideNonConfig ? mChildNonConfig : null);
                mChildNonConfig = null;
                mChildFragmentManager.dispatchCreate();
            }
        }
    }
    }

    /**
     * Called to have the fragment instantiate its user interface view.
@@ -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);
        }
    }

+7 −2
Original line number Diff line number Diff line
@@ -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;
                                }
                            }
                        }