如何应对Android面试官 -> 玩转 Fragment

前言


本章主要讲解下 Framgent 的核心原理;

基础用法


线上基础用法,其他的可以自行百度

scss 复制代码
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.contentlayout, "one", OneFragment);
transaction.commit();

// replace
// remove
// show
// hide
// addToBackStack
// setPrimaryNavigationFragment

生命周期


Fragment 的生命周期时序图;

Fragment 的生命周期时序管理是在 FragmentActivity 中进行的,我们来看下 Fragment 的生命周期是怎么和 Activity 进行绑定的;

我们从 onCreate 方法看起,可以看到这个 FragmentActivity 有很多关于 Framgent 分发的动作;

less 复制代码
protected void onCreate(@Nullable Bundle savedInstanceState) {
    // 省略部分代码
    this.mFragments.dispatchCreate();
}

其他的生命周期方法中 也都会有类似的动作,我们随便找一个看下:

typescript 复制代码
protected void onStart() {
    super.onStart();
    this.mFragments.dispatchStart();
}

而这个 mFraments 就是一个 FragmentController,它里面定义了一系列的 dispatch 逻辑

ini 复制代码
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

也就是 FragmentActivity 持有 FragmentController 间接持有了 FragmentHostCallback,通过这样的持有方式可以操作 Fragment 相关逻辑;

而所有的 dispatch 逻辑 最终都会走到 dispatchStateChange 方法,这个方法来分发一些 Fragment 身上的状态,总共是有下面这些状态

java 复制代码
static final int INITIALIZING = -1;          // Not yet attached.
static final int ATTACHED = 0;               // Attached to the host.
static final int CREATED = 1;                // Created.
static final int VIEW_CREATED = 2;           // View Created.
static final int AWAITING_EXIT_EFFECTS = 3;  // Downward state, awaiting exit effects
static final int ACTIVITY_CREATED = 4;       // Fully created, not started.
static final int STARTED = 5;                // Created and started, not resumed.
static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
static final int RESUMED = 7;

我们来探索下状态是怎么分发的,回到 dispatchStateChange 方法来;

ini 复制代码
private void dispatchStateChange(int nextState) {
    try {
        mExecutingActions = true;
        mFragmentStore.dispatchStateChange(nextState);
        moveToState(nextState, false);
        if (USE_STATE_MANAGER) {
            Set<SpecialEffectsController> controllers = collectAllSpecialEffectsController();
            for (SpecialEffectsController controller : controllers) {
                controller.forceCompleteAllOperations();
            }
        }
    } finally {
        mExecutingActions = false;
    }
    execPendingActions(true);
}

可以看到,不管什么状态进来,最终都是调用 moveToState 方法;

kotlin 复制代码
void moveToState(int newState, boolean always) {
    if (this.mHost == null && newState != 0) {
        throw new IllegalStateException("No activity");
    } else if (always || newState != this.mCurState) {
    
        // 赋值新传入进来的状态
        this.mCurState = newState;
        // 使用过的 Fragment 都会添加到 mAdded 中
        int numAdded = this.mAdded.size();

        Fragment f;
        for(int i = 0; i < numAdded; ++i) {
            f = (Fragment)this.mAdded.get(i);
            // 移动 Framgent 到期望的状态
            this.moveFragmentToExpectedState(f);
        }

        Iterator var6 = this.mActive.values().iterator();

        while(true) {
            do {
                do {
                    if (!var6.hasNext()) {
                        this.startPendingDeferredFragments();
                        if (this.mNeedMenuInvalidate && this.mHost != null && this.mCurState == 4) {
                            this.mHost.onSupportInvalidateOptionsMenu();
                            this.mNeedMenuInvalidate = false;
                        }

                        return;
                    }

                    f = (Fragment)var6.next();
                } while(f == null);
            } while(!f.mRemoving && !f.mDetached);

            if (!f.mIsNewlyAdded) {
                this.moveFragmentToExpectedState(f);
            }
        }
    }
}

我们进入这个 moveFragmentToExpectedState 方法看下:

ini 复制代码
void moveFragmentToExpectedState(Fragment f) {
    if (f != null) {
        if (!this.mActive.containsKey(f.mWho)) {
            if (DEBUG) {
                Log.v("FragmentManager", "Ignoring moving " + f + " to state " + this.mCurState + "since it is not added to " + this);
            }

        } else {
            int nextState = this.mCurState;
            if (f.mRemoving) {
                if (f.isInBackStack()) {
                    nextState = Math.min(nextState, 1);
                } else {
                    nextState = Math.min(nextState, 0);
                }
            }

            this.moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
            if (f.mView != null) {
                Fragment underFragment = this.findFragmentUnder(f);
                if (underFragment != null) {
                    View underView = underFragment.mView;
                    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) {
                    if (f.mPostponedAlpha > 0.0F) {
                        f.mView.setAlpha(f.mPostponedAlpha);
                    }

                    f.mPostponedAlpha = 0.0F;
                    f.mIsNewlyAdded = false;
                    AnimationOrAnimator anim = this.loadAnimation(f, f.getNextTransition(), true, f.getNextTransitionStyle());
                    if (anim != null) {
                        if (anim.animation != null) {
                            f.mView.startAnimation(anim.animation);
                        } else {
                            anim.animator.setTarget(f.mView);
                            anim.animator.start();
                        }
                    }
                }
            }

            if (f.mHiddenChanged) {
                this.completeShowHideFragment(f);
            }

        }
    }
}

这个方法也调度到了 moveToState 方法,我们来分析这个方法,这个方法比较长,我们一点一点来看

arduino 复制代码
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
    
    switch (f.mState) {
        case 0:
            
            this.dispatchOnFragmentPreAttached(f, this.mHost.getContext(), false);
            // 执行到这里,就会分发 Framgent 的 onAttach 方法
            f.performAttach();
            
            this.dispatchOnFragmentAttached(f, this.mHost.getContext(), false);
            // 如果没有创建,执行 create
            if (!f.mIsCreated) {
                this.dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                f.performCreate(f.mSavedFragmentState);
                this.dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
            } else {
                f.restoreChildFragmentState(f.mSavedFragmentState);
                f.mState = 1;
            }
        
    }
}

performAttach 方法:

ini 复制代码
void performAttach() {
    for (OnPreAttachedListener listener: mOnPreAttachedListeners) {
        listener.onPreAttached();
    }
    mOnPreAttachedListeners.clear();
    mChildFragmentManager.attachController(mHost, createFragmentContainer(), this);
    mState = ATTACHED;
    mCalled = false;
    // 回调 Fragment 的 onAttach 方法
    onAttach(mHost.getContext());
    if (!mCalled) {
        throw new SuperNotCalledException("Fragment " + this
                + " did not call through to super.onAttach()");
    }
    mFragmentManager.dispatchOnAttachFragment(this);
    mChildFragmentManager.dispatchAttach();
}

同理 performCreate 方法

less 复制代码
void performCreate(Bundle savedInstanceState) {
    mChildFragmentManager.noteStateNotSaved();
    // 同时更新状态,是为了让下一个状态能流转起来;
    mState = CREATED;
    mCalled = false;
    if (Build.VERSION.SDK_INT >= 19) {
        mLifecycleRegistry.addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_STOP) {
                    if (mView != null) {
                        mView.cancelPendingInputEvents();
                    }
                }
            }
        });
    }
    mSavedStateRegistryController.performRestore(savedInstanceState);
    // 回调 Fragment 的 onCreate 方法
    onCreate(savedInstanceState);
    mIsCreated = true;
    if (!mCalled) {
        throw new SuperNotCalledException("Fragment " + this
                + " did not call through to super.onCreate()");
    }
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}

所有的 performXXX 方法都执行两个核心操作,一个是更新状态,是为了让下一个状态能流转起来,另一个就是回调对应的 Fragment 的 XXX 方法;

因为源码中的这个 switch 中的每一个 case 都没有 break 关键字,可以一直流转下去;

所以,无论 Fragment 是从 onAttach 到 onResume 之间的任意一个方法进来,最终都会流转到 onResume 方法;

我们接着往下看 onCreateView 逻辑

arduino 复制代码
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
    
    switch (f.mState) {
        case 1:
            f.mContainer = container;
            // 创建 View
            f.performCreateView(f.performGetLayoutInflater(f.mSavedFragmentState), container, f.mSavedFragmentState);
            // 分发 ActivityCreated
            f.performActivityCreated(f.mSavedFragmentState);
            this.dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
    }
}

创建 View 的过程,还是调用的 inflater 的逻辑,创建 View 之后,分发 ActivityCreated 状态

就这样一直分发下去,直到 RESUME 的状态,RESUME 之后的生命周期变化就进入了 else 的逻辑;

arduino 复制代码
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { 
    if (f.mState <= newState) {
        // onAttach -> onResume
    } else if(f.mState > newState) {
        // onResume -> onDestroy
        
    }
}

我们来看下 else 的逻辑,执行到这里的时候,说明 Fragment 要退后台或者销毁了;整体的流转是和上面一样,从 resume -> pause -> stop -> destroyView -> destroy 这样的一个逻辑;

所以 Fragment 的生命周期分发就是这样实现的;

FragmentManager


getSupportFragmentManager() 最终拿到的是具体实现 FragmentManagerImpl;

FragmentTransaction


FragmentTransaction 的唯一实现就是 BackStackRecord;

csharp 复制代码
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

add

less 复制代码
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
        @Nullable String tag) {
    doAddOp(containerViewId, fragment, tag, OP_ADD);
    return this;
}

这个 OP_ADD 就是操作 Fragment 的标识

ini 复制代码
static final int OP_NULL = 0;
static final int OP_ADD = 1;
static final int OP_REPLACE = 2;
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
static final int OP_DETACH = 6;
static final int OP_ATTACH = 7;
static final int OP_SET_PRIMARY_NAV = 8;
static final int OP_UNSET_PRIMARY_NAV = 9;
static final int OP_SET_MAX_LIFECYCLE = 10;
less 复制代码
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    // 省略部分代码
    // 创建一个 Op 对象,将 标识 和当前 Fragment 存起来了
    addOp(new Op(opcmd, fragment));
}

创建一个 Op 对象,将 标识 和当前 Fragment 存起来了,然后存入到一个 mOps 的集合中;

ini 复制代码
void addOp(Op op) {
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

commit

同理,其他命令也都是同样的操作;添加之后的统一处理,都在 commit 中,我们进入这个 commit 方法看下:

commit 有四个实现 commit,commitAllowingStateLoss,commitNow,commitNowAllowingStateLoss

typescript 复制代码
@Override
public int commit() {
    return commitInternal(false);
}

@Override
public int commitAllowingStateLoss() {
    return commitInternal(true);
}

@Override
public void commitNow() {
    disallowAddToBackStack();
    mManager.execSingleAction(this, false);
}

@Override
public void commitNowAllowingStateLoss() {
    disallowAddToBackStack();
    mManager.execSingleAction(this, true);
}

我们可以看到 commit 和 commitAllowingStateLoss 都是调用的 commitInternal 只是传递的值不一样,这里 true 表示可以允许状态丢失,false 不允许状态丢失,我们进入这个 commitInternal 方法看下:

kotlin 复制代码
int commitInternal(boolean allowStateLoss) {
    if (this.mCommitted) {
        throw new IllegalStateException("commit already called");
    } else {
        if (FragmentManager.isLoggingEnabled(2)) {
            Log.v("FragmentManager", "Commit: " + this);
            LogWriter logw = new LogWriter("FragmentManager");
            PrintWriter pw = new PrintWriter(logw);
            this.dump("  ", pw);
            pw.close();
        }

        this.mCommitted = true;
        if (this.mAddToBackStack) {
            this.mIndex = this.mManager.allocBackStackIndex();
        } else {
            this.mIndex = -1;
        }
        // 这里要重点关注,将事务放入一个队列中
        this.mManager.enqueueAction(this, allowStateLoss);
        return this.mIndex;
    }
}

enqueueAction 将当前事务放到一个队列中;

typescript 复制代码
void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        if (this.mHost == null) {
            if (this.mDestroyed) {
                throw new IllegalStateException("FragmentManager has been destroyed");
            }

            throw new IllegalStateException("FragmentManager has not been attached to a host.");
        }

        this.checkStateLoss();
    }

    synchronized(this.mPendingActions) {
        if (this.mHost == null) {
            if (!allowStateLoss) {
                throw new IllegalStateException("Activity has been destroyed");
            }
        } else {
            // 将当前事务放到了一个集合中,用来存放事务的集合
            this.mPendingActions.add(action);
            this.scheduleCommit();
        }
    }
}

mPendingActions.add(action) 将当前事务放到了一个集合中,用来存放事务的集合,然后调用 scheduleCommit 进行提交;

kotlin 复制代码
void scheduleCommit() {
    synchronized(this.mPendingActions) {
        boolean postponeReady = this.mPostponedTransactions != null && !this.mPostponedTransactions.isEmpty();
        boolean pendingReady = this.mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            this.mHost.getHandler().removeCallbacks(this.mExecCommit);
            // 通过 handler 执行
            this.mHost.getHandler().post(this.mExecCommit);
            this.updateOnBackPressedCallbackEnabled();
        }

    }
}

this.mHost.getHandler().post(this.mExecCommit) 通过 handler 执行这个命令

csharp 复制代码
private Runnable mExecCommit = new Runnable() {
    public void run() {
        FragmentManager.this.execPendingActions(true);
    }
};

最终调度到 execPendingActions 这个方法中;也就是事务的执行是在主线程执行的;

kotlin 复制代码
boolean execPendingActions(boolean allowStateLoss) {
    this.ensureExecReady(allowStateLoss);

    boolean didSomething;
    // 重点关注的地方
    for(didSomething = false; this.generateOpsForPendingActions(this.mTmpRecords, this.mTmpIsPop); didSomething = true) {
        this.mExecutingActions = true;

        try {
            this.removeRedundantOperationsAndExecute(this.mTmpRecords, this.mTmpIsPop);
        } finally {
            this.cleanupExec();
        }
    }

    this.updateOnBackPressedCallbackEnabled();
    this.doPendingDeferredStart();
    this.mFragmentStore.burpActive();
    return didSomething;
}

generateOpsForPendingActions 生成操作为事务集合;

kotlin 复制代码
private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isPop) {
    boolean didSomething = false;
    synchronized(this.mPendingActions) {
        if (this.mPendingActions.isEmpty()) {
            return false;
        } else {
            int numActions = this.mPendingActions.size();

            for(int i = 0; i < numActions; ++i) {
                // 取出事务集合中的每一项,然后调用 generateOps 方法;
                didSomething |= ((OpGenerator)this.mPendingActions.get(i)).generateOps(records, isPop);
            }

            this.mPendingActions.clear();
            this.mHost.getHandler().removeCallbacks(this.mExecCommit);
            return didSomething;
        }
    }
}

取出事务集合中的每一项,然后调用 generateOps 方法,这个方法主要是将集合中的数据挪到了另一个集合中,并附带了一个标记;

less 复制代码
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isRecordPop) {
    if (FragmentManager.isLoggingEnabled(2)) {
        Log.v("FragmentManager", "Run: " + this);
    }

    records.add(this);
    isRecordPop.add(false);
    if (this.mAddToBackStack) {
        this.mManager.addBackStackState(this);
    }

    return true;
}

这个标记就是标记哪些事务是添加到了回退栈中,true 也就是调用了 addToBackStack,false 没有;也就是有栈操作和无栈操作是分两个集合运行的;

事务分完之后,执行 removeRedundantOperationsAndExecute 删除裁剪操作之后并执行

less 复制代码
private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isRecordPop) {
    if (!records.isEmpty()) {
        if (records.size() != isRecordPop.size()) {
            throw new IllegalStateException("Internal error with the back stack records");
        } else {
            this.executePostponedTransaction(records, isRecordPop);
            int numRecords = records.size();
            int startIndex = 0;

            for(int recordNum = 0; recordNum < numRecords; ++recordNum) {
                boolean canReorder = ((BackStackRecord)records.get(recordNum)).mReorderingAllowed;
                if (!canReorder) {
                    if (startIndex != recordNum) {
                        // 执行关联操作,是一个优化逻辑,例如 add->remove->add 这样的话前面两步就是多余操作,可以移除掉
                        this.executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                    }

                    int reorderingEnd = recordNum + 1;
                    if ((Boolean)isRecordPop.get(recordNum)) {
                        while(reorderingEnd < numRecords && (Boolean)isRecordPop.get(reorderingEnd) && !((BackStackRecord)records.get(reorderingEnd)).mReorderingAllowed) {
                            ++reorderingEnd;
                        }
                    }

                    this.executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
                    startIndex = reorderingEnd;
                    recordNum = reorderingEnd - 1;
                }
            }

            if (startIndex != numRecords) {
                this.executeOpsTogether(records, isRecordPop, startIndex, numRecords);
            }

        }
    }
}

executeOpsTogether 执行关联操作,是一个优化逻辑,例如 add->remove->add 这样的话前面两步就是多余操作,可以移除掉

ini 复制代码
private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    boolean allowReordering = ((BackStackRecord)records.get(startIndex)).mReorderingAllowed;
    boolean addToBackStack = false;
    if (this.mTmpAddedFragments == null) {
        this.mTmpAddedFragments = new ArrayList();
    } else {
        this.mTmpAddedFragments.clear();
    }

    this.mTmpAddedFragments.addAll(this.mFragmentStore.getFragments());
    Fragment oldPrimaryNav = this.getPrimaryNavigationFragment();

    int postponeIndex;
    for(postponeIndex = startIndex; postponeIndex < endIndex; ++postponeIndex) {
        BackStackRecord record = (BackStackRecord)records.get(postponeIndex);
        boolean isPop = (Boolean)isRecordPop.get(postponeIndex);
        // 这里执行的就是移除操作
        if (!isPop) {
            oldPrimaryNav = record.expandOps(this.mTmpAddedFragments, oldPrimaryNav);
        } else {
            oldPrimaryNav = record.trackAddedFragmentsInPop(this.mTmpAddedFragments, oldPrimaryNav);
        }

        addToBackStack = addToBackStack || record.mAddToBackStack;
    }

    this.mTmpAddedFragments.clear();
    if (!allowReordering) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex, false, this.mFragmentTransitionCallback);
    }
    // 前面逻辑走完之后,执行到这里
    executeOps(records, isRecordPop, startIndex, endIndex);
    postponeIndex = endIndex;
    if (allowReordering) {
        ArraySet<Fragment> addedFragments = new ArraySet();
        this.addAddedFragments(addedFragments);
        postponeIndex = this.postponePostponableTransactions(records, isRecordPop, startIndex, endIndex, addedFragments);
        this.makeRemovedFragmentsInvisible(addedFragments);
    }

    if (postponeIndex != startIndex && allowReordering) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, postponeIndex, true, this.mFragmentTransitionCallback);
        this.moveToState(this.mCurState, true);
    }

    for(int recordNum = startIndex; recordNum < endIndex; ++recordNum) {
        BackStackRecord record = (BackStackRecord)records.get(recordNum);
        boolean isPop = (Boolean)isRecordPop.get(recordNum);
        if (isPop && record.mIndex >= 0) {
            record.mIndex = -1;
        }

        record.runOnCommitRunnables();
    }

    if (addToBackStack) {
        this.reportBackStackChanged();
    }

}

executeOps 执行 Fragment 的操作

less 复制代码
private static void executeOps(@NonNull ArrayList<BackStackRecord> records, @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    for(int i = startIndex; i < endIndex; ++i) {
        BackStackRecord record = (BackStackRecord)records.get(i);
        boolean isPop = (Boolean)isRecordPop.get(i);
        if (isPop) {
            // 有栈
            record.bumpBackStackNesting(-1);
            boolean moveToState = i == endIndex - 1;
            record.executePopOps(moveToState);
        } else {
            // 无栈
            record.bumpBackStackNesting(1);
            record.executeOps();
        }
    }

}

这里也是分为两种,一种是有栈的,一种是无栈的,分开处理;我们来看下无栈的;

kotlin 复制代码
void executeOps() {
    int numOps = this.mOps.size();

    for(int opNum = 0; opNum < numOps; ++opNum) {
        FragmentTransaction.Op op = (FragmentTransaction.Op)this.mOps.get(opNum);
        Fragment f = op.mFragment;
        if (f != null) {
            f.setNextTransition(this.mTransition);
        }

        switch (op.mCmd) {
            case 1:
                f.setNextAnim(op.mEnterAnim);
                this.mManager.setExitAnimationOrder(f, false);
                // 执行 Framgent 的添加,添加之后就会走 Framgent 的生命周期
                this.mManager.addFragment(f);
                break;
            case 2:
            default:
                throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
            case 3:
                f.setNextAnim(op.mExitAnim);
                this.mManager.removeFragment(f);
                break;
            case 4:
                f.setNextAnim(op.mExitAnim);
                this.mManager.hideFragment(f);
                break;
            case 5:
                f.setNextAnim(op.mEnterAnim);
                this.mManager.setExitAnimationOrder(f, false);
                this.mManager.showFragment(f);
                break;
            case 6:
                f.setNextAnim(op.mExitAnim);
                this.mManager.detachFragment(f);
                break;
            case 7:
                f.setNextAnim(op.mEnterAnim);
                this.mManager.setExitAnimationOrder(f, false);
                this.mManager.attachFragment(f);
                break;
            case 8:
                this.mManager.setPrimaryNavigationFragment(f);
                break;
            case 9:
                this.mManager.setPrimaryNavigationFragment((Fragment)null);
                break;
            case 10:
                this.mManager.setMaxLifecycle(f, op.mCurrentMaxState);
        }

        if (!this.mReorderingAllowed && op.mCmd != 1 && f != null) {
            this.mManager.moveFragmentToExpectedState(f);
        }
    }

    if (!this.mReorderingAllowed) {
        this.mManager.moveToState(this.mManager.mCurState, true);
    }

}

this.mManager.addFragment(f) 执行 Framgent 的添加,添加之后通过 moveToState 就会执行对应的生命周期

moveToState -> moveFragmentToExpectedState -> moveToState 就会到我们前面看到的Fragment生命周期的 moveToState 来分发对应的生命周期

ini 复制代码
void moveToState(@NonNull Fragment f, int newState) {
    FragmentStateManager fragmentStateManager = this.mFragmentStore.getFragmentStateManager(f.mWho);
    if (fragmentStateManager == null) {
        fragmentStateManager = new FragmentStateManager(this.mLifecycleCallbacksDispatcher, f);
        fragmentStateManager.setFragmentManagerState(1);
    }

    newState = Math.min(newState, fragmentStateManager.computeMaxState());
    if (f.mState <= newState) {
        if (f.mState < newState && !this.mExitAnimationCancellationSignals.isEmpty()) {
            this.cancelExitAnimation(f);
        }

        switch (f.mState) {
            case -1:
                if (newState > -1) {
                    if (isLoggingEnabled(3)) {
                        Log.d("FragmentManager", "moveto ATTACHED: " + f);
                    }

                    if (f.mTarget != null) {
                        if (!f.mTarget.equals(this.findActiveFragment(f.mTarget.mWho))) {
                            throw new IllegalStateException("Fragment " + f + " declared target fragment " + f.mTarget + " that does not belong to this FragmentManager!");
                        }

                        if (f.mTarget.mState < 1) {
                            this.moveToState(f.mTarget, 1);
                        }

                        f.mTargetWho = f.mTarget.mWho;
                        f.mTarget = null;
                    }

                    if (f.mTargetWho != null) {
                        Fragment target = this.findActiveFragment(f.mTargetWho);
                        if (target == null) {
                            throw new IllegalStateException("Fragment " + f + " declared target fragment " + f.mTargetWho + " that does not belong to this FragmentManager!");
                        }

                        if (target.mState < 1) {
                            this.moveToState(target, 1);
                        }
                    }

                    fragmentStateManager.attach(this.mHost, this, this.mParent);
                }
            case 0:
                if (newState > 0) {
                    fragmentStateManager.create();
                }
            case 1:
                if (newState > -1) {
                    fragmentStateManager.ensureInflatedView();
                }

                if (newState > 1) {
                    fragmentStateManager.createView(this.mContainer);
                    fragmentStateManager.activityCreated();
                    fragmentStateManager.restoreViewState();
                }
            case 2:
                if (newState > 2) {
                    fragmentStateManager.start();
                }
            case 3:
                if (newState > 3) {
                    fragmentStateManager.resume();
                }
        }
    } else if (f.mState > newState) {
        switch (f.mState) {
            case 4:
                if (newState < 4) {
                    fragmentStateManager.pause();
                }
            case 3:
                if (newState < 3) {
                    fragmentStateManager.stop();
                }
            case 2:
                if (newState < 2) {
                    if (isLoggingEnabled(3)) {
                        Log.d("FragmentManager", "movefrom ACTIVITY_CREATED: " + f);
                    }

                    if (f.mView != null && this.mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                        fragmentStateManager.saveViewState();
                    }

                    FragmentAnim.AnimationOrAnimator anim = null;
                    if (f.mView != null && f.mContainer != null) {
                        f.mContainer.endViewTransition(f.mView);
                        f.mView.clearAnimation();
                        if (!f.isRemovingParent()) {
                            if (this.mCurState > -1 && !this.mDestroyed && f.mView.getVisibility() == 0 && f.mPostponedAlpha >= 0.0F) {
                                anim = FragmentAnim.loadAnimation(this.mHost.getContext(), this.mContainer, f, false);
                            }

                            f.mPostponedAlpha = 0.0F;
                            ViewGroup container = f.mContainer;
                            View view = f.mView;
                            if (anim != null) {
                                f.setStateAfterAnimating(newState);
                                FragmentAnim.animateRemoveFragment(f, anim, this.mFragmentTransitionCallback);
                            }

                            container.removeView(view);
                            if (container != f.mContainer) {
                                return;
                            }
                        }
                    }

                    if (this.mExitAnimationCancellationSignals.get(f) == null) {
                        this.destroyFragmentView(f);
                    } else {
                        f.setStateAfterAnimating(newState);
                    }
                }
            case 1:
                if (newState < 1) {
                    boolean beingRemoved = f.mRemoving && !f.isInBackStack();
                    if (!beingRemoved && !this.mNonConfig.shouldDestroy(f)) {
                        if (f.mTargetWho != null) {
                            Fragment target = this.findActiveFragment(f.mTargetWho);
                            if (target != null && target.getRetainInstance()) {
                                f.mTarget = target;
                            }
                        }
                    } else {
                        this.makeInactive(fragmentStateManager);
                    }

                    if (this.mExitAnimationCancellationSignals.get(f) != null) {
                        f.setStateAfterAnimating(newState);
                        newState = 1;
                    } else {
                        fragmentStateManager.destroy(this.mHost, this.mNonConfig);
                    }
                }
            case 0:
                if (newState < 0) {
                    fragmentStateManager.detach(this.mNonConfig);
                }
        }
    }

    if (f.mState != newState) {
        if (isLoggingEnabled(3)) {
            Log.d("FragmentManager", "moveToState: Fragment state for " + f + " not updated inline; expected state " + newState + " found " + f.mState);
        }

        f.mState = newState;
    }

}

addBackToStack

我们接下来看下 回退栈 addBackToStack

kotlin 复制代码
public FragmentTransaction addToBackStack(@Nullable String name) {
    if (!this.mAllowAddToBackStack) {
        throw new IllegalStateException("This FragmentTransaction is not allowed to be added to the back stack.");
    } else {
        this.mAddToBackStack = true;
        this.mName = name;
        return this;
    }
}

这里仅仅是把 mAddToBackStack 设置为 true,那么这个标志位在哪里使用的呢?就在前面我们说 commit 的时候;

kotlin 复制代码
if (this.mAddToBackStack) {
    this.mIndex = this.mManager.allocBackStackIndex();
}

allocBackStackIndex 这个方法我们来看下:

kotlin 复制代码
public int allocBackStackIndex(BackStackRecord bse) {
    synchronized(this) {
        int index;
        if (this.mAvailBackStackIndices != null && this.mAvailBackStackIndices.size() > 0) {
            index = (Integer)this.mAvailBackStackIndices.remove(this.mAvailBackStackIndices.size() - 1);
            if (DEBUG) {
                Log.v("FragmentManager", "Adding back stack index " + index + " with " + bse);
            }

            this.mBackStackIndices.set(index, bse);
            return index;
        } else {
            if (this.mBackStackIndices == null) {
                this.mBackStackIndices = new ArrayList();
            }
            // 如果是第一次,这里获取到的是 0
            index = this.mBackStackIndices.size();
            if (DEBUG) {
                Log.v("FragmentManager", "Setting back stack index " + index + " to " + bse);
            }
            // 将事务添加到这个集合中,并返回对应的 index;
            this.mBackStackIndices.add(bse);
            return index;
        }
    }
}

这里有一点比较饶,就是 this.mAvailBackStackIndices != null 这看起来好像一直不成立似的,就会导致一直都是走 else 逻辑进行添加,其实并不是,我们往下看有一个 freeBackStackSize 的逻辑;

typescript 复制代码
public void freeBackStackIndex(int index) {
    synchronized(this) {
        // 先把对应索引的值设置为 null
        this.mBackStackIndices.set(index, (Object)null);
        if (this.mAvailBackStackIndices == null) {
            this.mAvailBackStackIndices = new ArrayList();
        }

        if (DEBUG) {
            Log.v("FragmentManager", "Freeing back stack index " + index);
        }
        // 把索引存入这个集合中
        this.mAvailBackStackIndices.add(index);
    }
}

当我们要释放某个索引的时候,就会先把对应索引的值设置为 null 然后将对应的索引添加到 mAvailBackStackIndices 这个集合中,当我们下次添加的时候,此时 this.mAvailBackStackIndices != null 就会成立,就能进入对应的逻辑中

kotlin 复制代码
// 获取集合中最后一项的值,也就是存入的第一个索引值
index = (Integer)this.mAvailBackStackIndices.remove(this.mAvailBackStackIndices.size() - 1);

this.mBackStackIndices.set(index, bse);

获取对应的索引,并更新对应索引的值为对应的事务;回退栈逻辑就到这里了,我们接下来看下状态的保存和恢复。

onSaveInstanceState

通过 onSaveInstanceState 方法最终会调用到 FragmentController 的 saveAllState 方法

csharp 复制代码
public Parcelable saveAllState() {
    return mHost.mFragmentManager.saveAllState();
}

我们进入这个 saveAllState 方法看下:

ini 复制代码
Parcelable saveAllState() {
    this.forcePostponedTransactions();
    this.endAnimatingAwayFragments();
    this.execPendingActions();
    this.mStateSaved = true;
    if (this.mActive.isEmpty()) {
        return null;
    } else {
        int size = this.mActive.size();
        ArrayList<FragmentState> active = new ArrayList(size);
        boolean haveFragments = false;
        Iterator var4 = this.mActive.values().iterator();

        while(true) {
            Fragment f;
            Fragment target;
            do {
                if (!var4.hasNext()) {
                    if (!haveFragments) {
                        if (DEBUG) {
                            Log.v("FragmentManager", "saveAllState: no fragments!");
                        }

                        return null;
                    }

                    ArrayList<String> added = null;
                    BackStackState[] backStack = null;
                    size = this.mAdded.size();
                    if (size > 0) {
                        added = new ArrayList(size);
                        Iterator var10 = this.mAdded.iterator();

                        while(var10.hasNext()) {
                            target = (Fragment)var10.next();
                            added.add(target.mWho);
                            if (target.mFragmentManager != this) {
                                this.throwException(new IllegalStateException("Failure saving state: active " + target + " was removed from the FragmentManager"));
                            }

                            if (DEBUG) {
                                Log.v("FragmentManager", "saveAllState: adding fragment (" + target.mWho + "): " + target);
                            }
                        }
                    }

                    if (this.mBackStack != null) {
                        size = this.mBackStack.size();
                        if (size > 0) {
                            backStack = new BackStackState[size];

                            for(int i = 0; i < size; ++i) {
                                backStack[i] = new BackStackState((BackStackRecord)this.mBackStack.get(i));
                                if (DEBUG) {
                                    Log.v("FragmentManager", "saveAllState: adding back stack #" + i + ": " + this.mBackStack.get(i));
                                }
                            }
                        }
                    }

                    FragmentManagerState fms = new FragmentManagerState();
                    fms.mActive = active;
                    fms.mAdded = added;
                    fms.mBackStack = backStack;
                    if (this.mPrimaryNav != null) {
                        fms.mPrimaryNavActiveWho = this.mPrimaryNav.mWho;
                    }

                    fms.mNextFragmentIndex = this.mNextFragmentIndex;
                    return fms;
                }

                f = (Fragment)var4.next();
            } while(f == null);

            if (f.mFragmentManager != this) {
                this.throwException(new IllegalStateException("Failure saving state: active " + f + " was removed from the FragmentManager"));
            }

            haveFragments = true;
            FragmentState fs = new FragmentState(f);
            active.add(fs);
            if (f.mState > 0 && fs.mSavedFragmentState == null) {
                // 其他没什么值得关注的,重点是这里 saveFragmentBasicState
                fs.mSavedFragmentState = this.saveFragmentBasicState(f);
                if (f.mTargetWho != null) {
                    target = (Fragment)this.mActive.get(f.mTargetWho);
                    if (target == null) {
                        this.throwException(new IllegalStateException("Failure saving state: " + f + " has target not in fragment manager: " + f.mTargetWho));
                    }

                    if (fs.mSavedFragmentState == null) {
                        fs.mSavedFragmentState = new Bundle();
                    }

                    this.putFragment(fs.mSavedFragmentState, "android:target_state", target);
                    if (f.mTargetRequestCode != 0) {
                        fs.mSavedFragmentState.putInt("android:target_req_state", f.mTargetRequestCode);
                    }
                }
            } else {
                fs.mSavedFragmentState = f.mSavedFragmentState;
            }

            if (DEBUG) {
                Log.v("FragmentManager", "Saved state of " + f + ": " + fs.mSavedFragmentState);
            }
        }
    }
}

整体就是添加状态,其他没什么值得关注的,重点是这里 saveFragmentBasicState,我们的 Framgent 会解析 View 树,这里会把这个 View 树保存下来,我们进入这个方法看下:

kotlin 复制代码
Bundle saveFragmentBasicState(Fragment f) {
    Bundle result = null;
    if (this.mStateBundle == null) {
        this.mStateBundle = new Bundle();
    }

    f.performSaveInstanceState(this.mStateBundle);
    this.dispatchOnFragmentSaveInstanceState(f, this.mStateBundle, false);
    if (!this.mStateBundle.isEmpty()) {
        result = this.mStateBundle;
        this.mStateBundle = null;
    }

    if (f.mView != null) {
        // 保存这个 View 的状态
        this.saveFragmentViewState(f);
    }

    if (f.mSavedViewState != null) {
        if (result == null) {
            result = new Bundle();
        }

        result.putSparseParcelableArray("android:view_state", f.mSavedViewState);
    }

    if (!f.mUserVisibleHint) {
        if (result == null) {
            result = new Bundle();
        }

        result.putBoolean("android:user_visible_hint", f.mUserVisibleHint);
    }

    return result;
}

通过 saveFragmentViewState 来保存对应的 View 的状态;

kotlin 复制代码
void saveFragmentViewState(Fragment f) {
    if (f.mInnerView != null) {
        if (this.mStateArray == null) {
            this.mStateArray = new SparseArray();
        } else {
            this.mStateArray.clear();
        }

        f.mInnerView.saveHierarchyState(this.mStateArray);
        if (this.mStateArray.size() > 0) {
            f.mSavedViewState = this.mStateArray;
            this.mStateArray = null;
        }

    }
}

整体和 Activity 的状态保存很相似,最终也是存到了 Bundle 中,然后在界面重新创建的时候恢复

ini 复制代码
if (savedInstanceState != null) {
    Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
    mFragments.restoreSaveState(p);
}

restoreSaveState 整体逻辑就是把存入的数据 再取出来,感兴趣的可以自行看下源码;

好了,Framgent 就讲到这里吧,感谢您的观看

下一章预告


MVC、MVP、MVVM

欢迎三连


来都来了,点个关注点个赞吧,你的支持是我最大的动力~

相关推荐
松仔log4 小时前
Java中级——组合和继承
android·java·开发语言
我命由我123457 小时前
Jetpack Compose - MaterialExpressiveTheme 与 MaterialTheme、ColorScheme
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
lilian2338 小时前
Harmony os 技术实战|拼豆制图06:收藏 ID、生成记录与重启恢复怎么不打架
android·java·数据库·harmonyos
2601_955759628 小时前
ClaudeAPI成本中心与业务标签设计指南
android·java·数据库
余衫马9 小时前
2026最新版!Android Studio 极速安装与配置指南
android·ide·android studio
AFinalStone9 小时前
Android 7系统异常问题排查(五)Framework层(下)—System Server崩溃
android·tombstone·系统异常
AFinalStone9 小时前
Android 7系统异常问题排查(八)系统追踪—Trace机制与性能诊断
android·系统异常
极客猴子12 小时前
Android录音转写频繁卡顿?多款APP长时间会议场景稳定性实测
android·人工智能·智能手机·飞书
Kapaseker12 小时前
Boolean 变量到底该怎么命名?
android·kotlin
AFinalStone13 小时前
Android 7系统异常问题排查(六)应用异常(上)—ANR机制全解
android·系统异常