//FragmentManager.class privatevoidcheckStateLoss(){ if (this.isStateSaved()) { thrownew IllegalStateException("Can not perform this action after onSaveInstanceState"); } }
@SuppressWarnings("deprecation") voidmoveToState(@NonNull Fragment f, int newState){ FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho); if (fragmentStateManager == null) { // Ideally, we only call moveToState() on active Fragments. However, // in restoreSaveState() we can call moveToState() on retained Fragments // just to clean them up without them ever being added to mActive. // For these cases, a brand new FragmentStateManager is enough. fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher, mFragmentStore, f); // Only allow this FragmentStateManager to go up to CREATED at the most fragmentStateManager.setFragmentManagerState(Fragment.CREATED); } // When inflating an Activity view with a resource instead of using setContentView(), and // that resource adds a fragment using the <fragment> tag (i.e. from layout and in layout), // the fragment will move to the VIEW_CREATED state before the fragment manager // moves to CREATED. So when moving the fragment manager moves to CREATED and the // inflated fragment is already in VIEW_CREATED we need to move new state up from CREATED // to VIEW_CREATED. This avoids accidentally moving the fragment back down to CREATED // which would immediately destroy the Fragment's view. We rely on computeExpectedState() // to pull the state back down if needed. if (f.mFromLayout && f.mInLayout && f.mState == Fragment.VIEW_CREATED) { newState = Math.max(newState, Fragment.VIEW_CREATED); } newState = Math.min(newState, fragmentStateManager.computeExpectedState()); if (f.mState <= newState) { // If we are moving to the same state, we do not need to give up on the animation. if (f.mState < newState && !mExitAnimationCancellationSignals.isEmpty()) { // The fragment is currently being animated... but! Now we // want to move our state back up. Give up on waiting for the // animation and proceed from where we are. cancelExitAnimation(f); } switch (f.mState) { case Fragment.INITIALIZING: if (newState > Fragment.INITIALIZING) { fragmentStateManager.attach(); } // fall through case Fragment.ATTACHED: if (newState > Fragment.ATTACHED) { fragmentStateManager.create(); } // fall through case Fragment.CREATED: // We want to unconditionally run this anytime we do a moveToState that // moves the Fragment above INITIALIZING, including cases such as when // we move from CREATED => CREATED as part of the case fall through above. if (newState > Fragment.INITIALIZING) { fragmentStateManager.ensureInflatedView(); }
if (newState > Fragment.CREATED) { fragmentStateManager.createView(); } // fall through case Fragment.VIEW_CREATED: if (newState > Fragment.VIEW_CREATED) { fragmentStateManager.activityCreated(); } // fall through case Fragment.ACTIVITY_CREATED: if (newState > Fragment.ACTIVITY_CREATED) { fragmentStateManager.start(); } // fall through case Fragment.STARTED: if (newState > Fragment.STARTED) { fragmentStateManager.resume(); } } } elseif (f.mState > newState) { switch (f.mState) { case Fragment.RESUMED: if (newState < Fragment.RESUMED) { fragmentStateManager.pause(); } // fall through case Fragment.STARTED: if (newState < Fragment.STARTED) { fragmentStateManager.stop(); } // fall through case Fragment.ACTIVITY_CREATED: if (newState < Fragment.ACTIVITY_CREATED) { if (isLoggingEnabled(Log.DEBUG)) { Log.d(TAG, "movefrom ACTIVITY_CREATED: " + f); } if (f.mView != null) { // Need to save the current view state if not // done already. if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) { fragmentStateManager.saveViewState(); } } } // fall through case Fragment.VIEW_CREATED: if (newState < Fragment.VIEW_CREATED) { FragmentAnim.AnimationOrAnimator anim = null; if (f.mView != null && f.mContainer != null) { // Stop any current animations: f.mContainer.endViewTransition(f.mView); f.mView.clearAnimation(); // If parent is being removed, no need to handle child animations. if (!f.isRemovingParent()) { if (mCurState > Fragment.INITIALIZING && !mDestroyed && f.mView.getVisibility() == View.VISIBLE && f.mPostponedAlpha >= 0) { anim = FragmentAnim.loadAnimation(mHost.getContext(), f, false, f.getPopDirection()); } f.mPostponedAlpha = 0; // Robolectric tests do not post the animation like a real device // so we should keep up with the container and view in case the // fragment view is destroyed before we can remove it. ViewGroup container = f.mContainer; View view = f.mView; if (anim != null) { FragmentAnim.animateRemoveFragment(f, anim, mFragmentTransitionCallback); } container.removeView(view); if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) { Log.v(FragmentManager.TAG, "Removing view " + view + " for " + "fragment " + f + " from container " + container); } // If the local container is different from the fragment // container, that means onAnimationEnd was called, onDestroyView // was dispatched and the fragment was already moved to state, so // we should early return here instead of attempting to move to // state again. if (container != f.mContainer) { return; } } } // If a fragment has an exit animation (or transition), do not destroy // its view immediately and set the state after animating if (mExitAnimationCancellationSignals.get(f) == null) { fragmentStateManager.destroyFragmentView(); } } // fall through case Fragment.CREATED: if (newState < Fragment.CREATED) { if (mExitAnimationCancellationSignals.get(f) != null) { // We are waiting for the fragment's view to finish animating away. newState = Fragment.CREATED; } else { fragmentStateManager.destroy(); } } // fall through case Fragment.ATTACHED: if (newState < Fragment.ATTACHED) { fragmentStateManager.detach(); } } }
if (f.mState != newState) { if (isLoggingEnabled(Log.DEBUG)) { Log.d(TAG, "moveToState: Fragment state for " + f + " not updated inline; " + "expected state " + newState + " found " + f.mState); } f.mState = newState; } }