voidattachController(@NonNull FragmentHostCallback<?> host, @NonNull FragmentContainer container, @Nullablefinal Fragment parent){ if (mHost != null) thrownew IllegalStateException("Already attached"); mHost = host; mContainer = container; mParent = parent; if (mParent != null) { // Since the callback depends on us being the primary navigation fragment, // update our callback now that we have a parent so that we have the correct // state by default updateOnBackPressedCallbackEnabled(); } // Set up the OnBackPressedCallback if (host instanceof OnBackPressedDispatcherOwner) { OnBackPressedDispatcherOwner dispatcherOwner = ((OnBackPressedDispatcherOwner) host); mOnBackPressedDispatcher = dispatcherOwner.getOnBackPressedDispatcher(); LifecycleOwner owner = parent != null ? parent : dispatcherOwner; mOnBackPressedDispatcher.addCallback(owner, mOnBackPressedCallback); }
// Get the FragmentManagerViewModel if (parent != null) { mNonConfig = parent.mFragmentManager.getChildNonConfig(parent); } elseif (host instanceof ViewModelStoreOwner) { ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore(); mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore); } else { mNonConfig = new FragmentManagerViewModel(false); } }
publicabstractclassFragmentTransaction{ public FragmentTransaction add(@IdResint containerViewId, @NonNull Fragment fragment){ doAddOp(containerViewId, fragment, null, OP_ADD); returnthis; } voiddoAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd){ final Class<?> fragmentClass = fragment.getClass(); finalint modifiers = fragmentClass.getModifiers(); if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers) || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) { thrownew IllegalStateException("Fragment " + fragmentClass.getCanonicalName() + " must be a public static class to be properly recreated from" + " instance state."); }
if (tag != null) { if (fragment.mTag != null && !tag.equals(fragment.mTag)) { thrownew IllegalStateException("Can't change tag of fragment " + fragment + ": was " + fragment.mTag + " now " + tag); } fragment.mTag = tag; }
//---------------------存储containerViewId到fragment中-------------- if (containerViewId != 0) { if (containerViewId == View.NO_ID) { thrownew IllegalArgumentException("Can't add fragment " + fragment + " with tag " + tag + " to container view with no id"); } if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { thrownew IllegalStateException("Can't change container ID of fragment " + fragment + ": was " + fragment.mFragmentId + " now " + containerViewId); } fragment.mContainerId = fragment.mFragmentId = containerViewId; }
privatefinal ArrayList<OpGenerator> mPendingActions = new ArrayList<>();
voidenqueueAction(@NonNull OpGenerator action, boolean allowStateLoss){ if (!allowStateLoss) { //不允许状态改变 if (mHost == null) { if (mDestroyed) { thrownew IllegalStateException("FragmentManager has been destroyed"); } else { thrownew IllegalStateException("FragmentManager has not been attached to a " + "host."); } } checkStateLoss();//如果已经改变,就在在这个方法内抛错 } synchronized (mPendingActions) { if (mHost == null) { if (allowStateLoss) { // This FragmentManager isn't attached, so drop the entire transaction. return; } thrownew IllegalStateException("Activity has been destroyed"); } mPendingActions.add(action); scheduleCommit(); } }
if (records.size() != isRecordPop.size()) { thrownew IllegalStateException("Internal error with the back stack records"); }
// Force start of any postponed transactions that interact with scheduled transactions: //强制启动所有 与计划的transactions交互的 延迟的 transactions。即完成以前已延迟但现在已准备好的事务的transactions executePostponedTransaction(records, isRecordPop);
finalint numRecords = records.size(); int startIndex = 0; for (int recordNum = 0; recordNum < numRecords; recordNum++) { // 标记是否支持操作排序优化,默认为false finalboolean canReorder = records.get(recordNum).mReorderingAllowed; if (!canReorder) { // execute all previous transactions if (startIndex != recordNum) { executeOpsTogether(records, isRecordPop, startIndex, recordNum); } // execute all pop operations that don't allow reordering together or // one add operation int reorderingEnd = recordNum + 1; // 非pop事务都返回false if (isRecordPop.get(recordNum)) { while (reorderingEnd < numRecords && isRecordPop.get(reorderingEnd) && !records.get(reorderingEnd).mReorderingAllowed) { reorderingEnd++; } } executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd); startIndex = reorderingEnd; recordNum = reorderingEnd - 1; } } if (startIndex != numRecords) { // 开启操作排序优化情况下可能会满足该if条件 executeOpsTogether(records, isRecordPop, startIndex, numRecords); } }
int postponeIndex = endIndex; if (allowReordering) { ArraySet<Fragment> addedFragments = new ArraySet<>(); addAddedFragments(addedFragments); postponeIndex = postponePostponableTransactions(records, isRecordPop, startIndex, endIndex, addedFragments); makeRemovedFragmentsInvisible(addedFragments); }
if (postponeIndex != startIndex && allowReordering) { // need to run something now FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, postponeIndex, true, mFragmentTransitionCallback); moveToState(mCurState, true); }
for (int recordNum = startIndex; recordNum < endIndex; recordNum++) { final BackStackRecord record = records.get(recordNum); finalboolean isPop = isRecordPop.get(recordNum); if (isPop && record.mIndex >= 0) { record.mIndex = -1; } record.runOnCommitRunnables(); } if (addToBackStack) { reportBackStackChanged(); } }
privatestaticvoidexecuteOps(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex){ for (int i = startIndex; i < endIndex; i++) { final BackStackRecord record = records.get(i); finalboolean isPop = isRecordPop.get(i); if (isPop) { record.bumpBackStackNesting(-1); // Only execute the add operations at the end of // all transactions. boolean moveToState = i == (endIndex - 1); record.executePopOps(moveToState); } else { record.bumpBackStackNesting(1); record.executeOps(); } } }
voidexecuteOps(){ finalint numOps = mOps.size(); for (int opNum = 0; opNum < numOps; opNum++) { final Op op = mOps.get(opNum); final Fragment f = op.mFragment; if (f != null) { f.setNextTransition(mTransition); } switch (op.mCmd) { case OP_ADD: f.setNextAnim(op.mEnterAnim); mManager.setExitAnimationOrder(f, false); mManager.addFragment(f); break; case OP_REMOVE: f.setNextAnim(op.mExitAnim); mManager.removeFragment(f); break; case OP_HIDE: f.setNextAnim(op.mExitAnim); mManager.hideFragment(f); break; case OP_SHOW: f.setNextAnim(op.mEnterAnim); mManager.setExitAnimationOrder(f, false); mManager.showFragment(f); break; case OP_DETACH: f.setNextAnim(op.mExitAnim); mManager.detachFragment(f); break; case OP_ATTACH: f.setNextAnim(op.mEnterAnim); mManager.setExitAnimationOrder(f, false); mManager.attachFragment(f); break; case OP_SET_PRIMARY_NAV: mManager.setPrimaryNavigationFragment(f); break; case OP_UNSET_PRIMARY_NAV: mManager.setPrimaryNavigationFragment(null); break; case OP_SET_MAX_LIFECYCLE: mManager.setMaxLifecycle(f, op.mCurrentMaxState); break; default: thrownew IllegalArgumentException("Unknown cmd: " + op.mCmd); } if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) { mManager.moveFragmentToExpectedState(f); } } if (!mReorderingAllowed) { // Added fragments are added at the end to comply with prior behavior. mManager.moveToState(mManager.mCurState, true); } }
// Must add them in the proper order. mActive fragments may be out of order for (Fragment f : mFragmentStore.getFragments()) { moveFragmentToExpectedState(f); }
// Now iterate through all active fragments. These will include those that are removed // and detached. for (Fragment f : mFragmentStore.getActiveFragments()) { if (f != null && !f.mIsNewlyAdded) { moveFragmentToExpectedState(f); } }
voidmoveFragmentToExpectedState(@NonNull Fragment f){ if (!mFragmentStore.containsActiveFragment(f.mWho)) { if (isLoggingEnabled(Log.DEBUG)) { Log.d(TAG, "Ignoring moving " + f + " to state " + mCurState + "since it is not added to " + this); } return; } moveToState(f);
if (f.mView != null) { // Move the view if it is out of order Fragment underFragment = mFragmentStore.findFragmentUnder(f); if (underFragment != null) { final View underView = underFragment.mView; // make sure this fragment is in the right order. final ViewGroup container = f.mContainer; int underIndex = container.indexOfChild(underView); int viewIndex = container.indexOfChild(f.mView); if (viewIndex < underIndex) { container.removeViewAt(viewIndex); container.addView(f.mView, underIndex); } } if (f.mIsNewlyAdded && f.mContainer != null) { // Make it visible and run the animations if (f.mPostponedAlpha > 0f) { f.mView.setAlpha(f.mPostponedAlpha); } f.mPostponedAlpha = 0f; f.mIsNewlyAdded = false; // run animations: FragmentAnim.AnimationOrAnimator anim = FragmentAnim.loadAnimation( mHost.getContext(), mContainer, f, true); if (anim != null) { if (anim.animation != null) { f.mView.startAnimation(anim.animation); } else { anim.animator.setTarget(f.mView); anim.animator.start(); } } } } if (f.mHiddenChanged) { completeShowHideFragment(f); } }
voidmoveToState(@NonNull Fragment f){ moveToState(f, mCurState); }
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, f); // Only allow this FragmentStateManager to go up to CREATED at the most fragmentStateManager.setFragmentManagerState(Fragment.CREATED); } newState = Math.min(newState, fragmentStateManager.computeMaxState()); 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) { if (isLoggingEnabled(Log.DEBUG)) Log.d(TAG, "moveto ATTACHED: " + f);
// If we have a target fragment, push it along to at least CREATED // so that this one can rely on it as an initialized dependency. if (f.mTarget != null) { if (!f.mTarget.equals(findActiveFragment(f.mTarget.mWho))) { thrownew IllegalStateException("Fragment " + f + " declared target fragment " + f.mTarget + " that does not belong to this FragmentManager!"); } if (f.mTarget.mState < Fragment.CREATED) { moveToState(f.mTarget, Fragment.CREATED); } f.mTargetWho = f.mTarget.mWho; f.mTarget = null; } if (f.mTargetWho != null) { Fragment target = findActiveFragment(f.mTargetWho); if (target == null) { thrownew IllegalStateException("Fragment " + f + " declared target fragment " + f.mTargetWho + " that does not belong to this FragmentManager!"); } if (target.mState < Fragment.CREATED) { moveToState(target, Fragment.CREATED); } }
fragmentStateManager.attach(mHost, this, mParent); } // 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(mContainer); fragmentStateManager.activityCreated(); fragmentStateManager.restoreViewState(); } // 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) { .... }
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; } }
voidperformAttach(){ mChildFragmentManager.attachController(mHost, new FragmentContainer() { @Override @Nullable public View onFindViewById(int id){ if (mView == null) { thrownew IllegalStateException("Fragment " + this + " does not have a view"); } return mView.findViewById(id); }
@Override publicbooleanonHasView(){ return (mView != null); } }, this); mState = ATTACHED; mCalled = false; onAttach(mHost.getContext()); if (!mCalled) { thrownew SuperNotCalledException("Fragment " + this + " did not call through to super.onAttach()"); } }
voidperformCreate(Bundle savedInstanceState){ mChildFragmentManager.noteStateNotSaved(); mState = CREATED; mCalled = false; mSavedStateRegistryController.performRestore(savedInstanceState); onCreate(savedInstanceState); mIsCreated = true; if (!mCalled) { thrownew SuperNotCalledException("Fragment " + this + " did not call through to super.onCreate()"); } mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); }