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

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

Fix bugs around inflated child fragments

Framework edition

* Ensure that a fragment that has had its view destroyed has a chance
  to recreate it.

* Clear mInLayout after views are destroyed

* Make sure that when a fragment is restored from the back stack and
  reinflates its view that child fragments from fragment tags are
  reconnected properly.

Bug: 32691935
Test: cts
Change-Id: I370d6db46e72fd8ac35f716e2130b9e10b93b1da
parent ac4a8b7f
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -414,6 +414,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
    // True if this fragment has been restored from previously saved state.
    boolean mRestored;

    // True if performCreateView has been called and a matching call to performDestroyView
    // has not yet happened.
    boolean mPerformedCreateView;

    // Number of active back stack entries this fragment is in.
    int mBackStackNesting;

@@ -611,7 +615,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
            Fragment f = (Fragment)clazz.newInstance();
            if (args != null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.mArguments = args;
                f.setArguments(args);
            }
            return f;
        } catch (ClassNotFoundException e) {
@@ -2464,6 +2468,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        mPerformedCreateView = true;
        return onCreateView(inflater, container, savedInstanceState);
    }

@@ -2690,6 +2695,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
        if (mLoaderManager != null) {
            mLoaderManager.doReportNextStart();
        }
        mPerformedCreateView = false;
    }

    void performDestroy() {
+65 −55
Original line number Diff line number Diff line
@@ -1072,7 +1072,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
            newState = Fragment.STOPPED;
        }
        if (f.mState < newState) {
        if (f.mState <= newState) {
            // For fragments that are created from a layout, when restoring from
            // state we don't want to allow them to be created until they are
            // being reloaded from the layout.
@@ -1089,6 +1089,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
            }
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                        if (f.mSavedFragmentState != null) {
                            f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
@@ -1134,20 +1135,13 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
                            f.mState = Fragment.CREATED;
                        }
                        f.mRetaining = false;
                    if (f.mFromLayout) {
                        // For fragments that are part of the content view
                        // layout, we need to instantiate the view immediately
                        // and the inflater will take care of adding it.
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mView.setSaveFromParentEnabled(false);
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                            dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
                        }
                    }
                case Fragment.CREATED:
                    // This is outside the if statement below on purpose; we want this to run
                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
                    // * => CREATED as part of the case fallthrough above.
                    ensureInflatedFragmentView(f);

                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
@@ -1281,6 +1275,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
                        }
                        f.mContainer = null;
                        f.mView = null;
                        f.mInLayout = false;
                    }
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
@@ -1340,6 +1335,19 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
        moveToState(f, mCurState, 0, 0, false);
    }

    void ensureInflatedFragmentView(Fragment f) {
        if (f.mFromLayout && !f.mPerformedCreateView) {
            f.mView = f.performCreateView(f.getLayoutInflater(
                    f.mSavedFragmentState), null, f.mSavedFragmentState);
            if (f.mView != null) {
                f.mView.setSaveFromParentEnabled(false);
                if (f.mHidden) f.mView.setVisibility(View.GONE);
                f.onViewCreated(f.mView, f.mSavedFragmentState);
                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
            }
        }
    }

    /**
     * Fragments that have been shown or hidden don't have their visibility changed or
     * animations run during the {@link #showFragment(Fragment)} or {@link #hideFragment(Fragment)}
@@ -3262,7 +3270,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
        }

        // If we haven't finished entering the CREATED state ourselves yet,
        // push the inflated child fragment along.
        // push the inflated child fragment along. This will ensureInflatedFragmentView
        // at the right phase of the lifecycle so that we will have mView populated
        // for compliant fragments below.
        if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
            moveToState(fragment, Fragment.CREATED, 0, 0, false);
        } else {