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

会员管理小程序实战开发04-用户登录及注册 上一节我们介绍了用户信息数据源的创建及网格布局的使用,本节的话我们讲解用户的登录及注册功能任何开发。 在我们前述章节里介绍的,不论是管理员表还是用户表,都涉及到一个问题就是openid,那这个openid如何获取呢?如果我直接把代码贴给你,就缺失了一个思考的过程。既然这个是微信提出的概念,那么必然就会有官方文档作为对应。程序开发的基本功就是要会看官方文档,很多初学的开发同学可能会对官方文档颇有诟病,觉得不够基础。怎么说呢,当你进入到开发岗之后,自学能力是必要的,还是要试着可以看懂官方文档才好。 登录接口解读 阅读详情

前言


image.png

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

基础用法


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

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

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

生命周期


image.png

Fragment 的生命周期时序图;

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

image.png

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

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

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

protected void onStart() {
    super.onStart();
    this.mFragments.dispatchStart();
}

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

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

image.png

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

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

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 方法来;

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 方法;

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 方法看下:

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 方法,我们来分析这个方法,这个方法比较长,我们一点一点来看

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 方法:

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 方法

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 逻辑

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 的逻辑;

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;

public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

add

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

这个 OP_ADD 就是操作 Fragment 的标识

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;
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    // 省略部分代码
    // 创建一个 Op 对象,将 标识 和当前 Fragment 存起来了
    addOp(new Op(opcmd, fragment));
}

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

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

@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 方法看下:

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 将当前事务放到一个队列中;

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 进行提交;

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 执行这个命令

private Runnable mExecCommit = new Runnable() {
    public void run() {
        FragmentManager.this.execPendingActions(true);
    }
};

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

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 生成操作为事务集合;

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 方法,这个方法主要是将集合中的数据挪到了另一个集合中,并附带了一个标记;

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 删除裁剪操作之后并执行

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 这样的话前面两步就是多余操作,可以移除掉

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 的操作

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();
        }
    }

}

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

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 来分发对应的生命周期

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

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 的时候;

if (this.mAddToBackStack) {
    this.mIndex = this.mManager.allocBackStackIndex();
}

allocBackStackIndex 这个方法我们来看下:

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 的逻辑;

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 就会成立,就能进入对应的逻辑中

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

this.mBackStackIndices.set(index, bse);

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

onSaveInstanceState

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

public Parcelable saveAllState() {
    return mHost.mFragmentManager.saveAllState();
}

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

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 树保存下来,我们进入这个方法看下:

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 的状态;

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 中,然后在界面重新创建的时候恢复

if (savedInstanceState != null) {
    Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
    mFragments.restoreSaveState(p);
}

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

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

下一章预告


MVC、MVP、MVVM

欢迎三连


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

PCIe 6.0 – 关于 PCI Express Gen6 您需要知道的一切 幸运的是,PCIe 6.0 FEC 足够轻,对延迟的影响最小。在电气层上,PCIe 6.0 使用 PAM4 信号(“四级脉冲幅度调制”),每个时钟周期将 2 位组合为 4 个幅度级别(00、01、10、11),与 PCIe 5.0 和前几代相比,它使用 NRZ 调制,每个时钟周期 1 位和两个幅度级别 (0, 1)。虽然 PAM4 信号更容易出错,但由于调制技术的性质,与 PCIe 5.0 相比,通道损耗不受影响,因此 PCB 上 PCIe 6.0 信号的范围将与 PCIe 5.0 相同。 阅读详情

相关推荐

手把手教你用PlantVillage数据集搭建农作物病害识别模型(Python实战)

本文详细介绍了如何使用PlantVillage数据集和Python构建农作物病害识别模型。从环境准备、数据获取到模型构建、训练与评估,手把手教你实现一个实用的农业AI应用。特别针对PlantVillage数据集的特点,提供了处理类别不平衡、图像预处理和模型优化的实战技巧,帮助开发者快速掌握农作物病害识别技术。

weixin_29184371的博客 479

FragmentManager has been destroyed

FragmentManager has been destroyed

ss520k的专栏 1880

从寄存器配置到G值:一份给STM32开发者的SC7A20加速度数据换算保姆级指南

本文为STM32开发者提供SC7A20三轴加速度传感器的数据换算保姆级指南,详细解析从寄存器配置到G值转换的全过程。涵盖量程选择、输出值换算原理及优化代码实现,帮助开发者快速掌握加速度数据的物理意义转换技巧,提升运动感知系统开发效率。

weixin_29172963的博客 172

Fragment嵌套Fragment多次切换两次会出现Activity has been destroyed错误的解决办法

在嵌套子Fragment中的onDetach()方法中增加代码如下: @Override     public void onDetach()     {         super.onDetach();         try         {             Field childFragmentManager = Fragment.class.getDeclared

baiyi168的专栏 3879

从Power到HO:一文搞懂主流脑图谱在DPABI里怎么选,让你的rs-fMRI分析更精准

本文深入解析了rs-fMRI分析中主流脑图谱(如Power、HO、AAL等)在DPABI中的科学选择策略,帮助研究者根据不同的神经科学研究目标优化分析流程。从解剖学图谱到功能连接图谱的特性对比,到DPABI实操中的多图谱分析工作流,提供了全面的方法论指导,助力提升静息态功能磁共振成像(rs-fMRI)研究的精准度和可重复性。

weixin_30654583的博客 403

保姆级教程:Unity编辑器汉化全流程(从下载到配置避坑指南)

本文提供Unity编辑器汉化的保姆级教程,涵盖从下载中文语言包到配置避坑的全流程。详细解析版本适配、文件系统交互及编辑器底层配置逻辑,帮助开发者高效完成汉化,解决常见报错问题,提升工作效率。

weixin_30825581的博客 155

DialogFragment使用中show()方法遇到的IllegalStateException

最近在首页做了一个弹窗,用dialogFragment 实现的,线上报了一个crash: ava.lang.IllegalStateException: Can not perform

dearbaba_8520的博客 945

【ACP】2025-最新-疑难题解析-1

即用户手动释放时,因实例释放保护开启,不会释放该 ECS 实例(不同云厂商具体实现有差异,但题目场景下选 C )。结合题目中标记,答案为。综上,答案选 B。综上,答案选 C。综上,答案选 D。综上,答案选 A。综上,答案选 A。综上,答案选 C。综上,答案选 D。综上,答案选 A。

jundao1997的专栏 364

通过自定义FragmentController的FragmentHostCallback实现浮窗界面的管理

效果 FragmentController介绍 FragmentController用于控制fragment,它把activity的许多事件分发给fragment处理。更准确的说法是分配给fragment manager,然后由fragment manager分发给fragment。FragmentController通常都是在activity中创建的,并且activity作为FragmentC...

DragonCoding的专栏 1240

UDF学习(四)FLUENT UDF-DEFINE_PROFILE宏

利用DEFINE_PROFLILE可以指定以下边界或计算域信息:DEFINE_PROFILE(name,t,i)//既可以用。

weixin_44386973的博客 1806

【光子AI / Photon.AI】manus 通用 Agent 的实现核心技术原理与应用

摘要 Manus是一款由国内团队开发的通用AI Agent,其核心技术原理基于多智能体协作架构、云端全能沙箱、规划-执行-反思循环等系统工程方法。与传统的对话式AI不同,Manus能够在独立的Linux虚拟机环境中自主规划并执行复杂任务,通过编写和运行代码来解决问题,具备强大的纠错能力和工具使用能力。 核心应用场景包括深度行业研究、自动化办公、生活助理、辅助编程和跨平台信息整合等。Manus的工程化落地优势体现在沙箱环境、多智能体调度和容错机制等方面,使其能够完成需要多步骤操作和多种工具调用的复杂任务,将A

AI天才研究院 666

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

本文介绍了Android Navigation框架的基础使用。Navigation是用于在应用内不同目标(如Fragment、Activity)之间导航的框架。文章展示了一个简单示例,包含三个Fragment的跳转流程:MainPageFragment1通过按钮点击导航到MainPageFragment2,后者又提供返回或跳转到MainPageFragment3的选项。关键实现包括:1)添加Navigation依赖;2)创建Fragment布局文件;3)使用Navigation.findNavControl

IT_Android的博客 888

手把手教你学Simulink--基于Simulink的微电网用DC-DC变换器仿真建模

微电网概述微电网:包括可再生能源发电设备、储能系统和负载,可以独立于大电网运行,也可以并网运行。重要性提高能源可靠性:通过本地化供电减少对外部电网的依赖。促进可再生能源利用:支持高效整合多种可再生能源。挑战多源管理:不同类型的能源产生方式各异,需设计灵活的电源管理系统。能量转换效率:需要高效的能量转换装置来确保能源的有效利用。通过上述步骤,我们简要介绍了如何基于Simulink进行微电网中DC-DC变换器的仿真建模。

MHD0815的博客 161

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

本文介绍了Jetpack中的Lifecycle组件,用于监听Activity/Fragment生命周期变化。Lifecycle通过观察者模式实现,包含LifecycleOwner(如Activity/Fragment)和LifecycleObserver(观察者)。基础使用包括添加依赖库,通过实现LifecycleObserver接口或DefaultLifecycleObserver来监听生命周期事件。示例展示了如何在Presenter中监听Activity的生命周期变化,无需手动调用生命周期方法。该组件可

IT_Android的博客 996

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

如何应对Android面试官-> 玩转 ViewPager 懒加载

通常我们 ViewPager 在使用的是一般都是结合 Fragment 一起使用,我们先来搭一个简单的使用界面,最终搭建出来的效果如下:简单的 ViewPager + Fragment 的实现,比较简单,就不贴代码的实现了,我们接下来内容的讲解;页面可见的时候才进行加载;依托这个 setUserVisibleHint(isVisibleToUser: Boolean) 来实现懒加载;ViewPager渲染原理。

BASK2311的博客 1263

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

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

ViewBinding 基础使用与原理 ViewBinding 是 Android 官方推荐的视图绑定方案,用于替代 findViewById 和 ButterKnife。启用方法是在模块的 build.gradle 中配置 viewBinding { enabled true },系统会自动生成绑定类(如 ActivityMainBinding)。使用时只需调用 inflate() 方法绑定布局,即可直接访问视图控件(如 mainBinding.tv1.setText())。 相比 Kotlin 的合成绑

IT_Android的博客 837

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

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

本文介绍了Android开发中ViewModel的基础使用和原理。ViewModel作为数据容器,可以在配置变化时保持数据稳定,减轻Activity负担,并在多个组件间共享数据。文章通过一个拨号键盘Demo展示了ViewModel结合LiveData、DataBinding和Lifecycle的使用方式:继承ViewModel类存储数据,通过ViewModelProvider获取实例,在布局文件中绑定数据,实现数据持久化和界面更新。Demo还演示了ViewModel如何保存拨号状态,并通过系统API实现拨号

IT_Android的博客 1107

Fragment 生命周期源码分析

文章目录1.supportFragmentManager1.1 getSupportFragmentManager1.2 FragmentController类1.3 FragmentHostCallback类2.beginTransaction2.1 FragmentTransaction类2.2 Op类2.3 BackStackRecord类3.add,hide,replace,remove3.1 封装,addOp4.commit4.1 四种提交方式4.2 提交事务4.3 handler 发送4.4 执

Good包籽的Android专栏 649

时序图的Fragments的解说

针对Sequence中的各种Fragments进行详细的解说。

Leonard的专栏 2076

FragmentController类管理Fragment时偶尔报activity has been destroyed

在新开发的项目中,第一次启动MainActivity时,程序能正常运行,退出应用再次启动时程序崩溃,(反复启动、退出应用时,偶尔程序崩溃)报错如下:AndroidRuntime: FATAL EXCEPTION: main Process: com.dell, PID: 16 java.lang.RuntimeException: Unable to start activity Componen...

qq_35442755的博客 4212

Fragment全文详解(由浅入深_源码分析)

相信android开发者们一定或多或少的用过Fragment,但是对于其更深层次的原理我猜可能大部分应该都没有了解过,今天这里就由浅入深,整体对Fragment做一个全面解析。

Pumpkin's Blog 3680

Android-Fragment源码解析

UML类图 主要类含义介绍 FragmentController FragmentController为Fragment的宿主提供一个控制器,对Fragment生命周期操作,提供一个控制流程。FragmentController中持有FragmentHostCallback对象,对于Fragment生命周期的操作,主要是通过FragmentHostCallback来实现的。而Fragm...

Abe的学习之路 1137

activity调用fragment的方法_Fragment事务流程分析

Fragment事务流程分析简言简单的事务使用流程代码getSupportFragmentManager使用的方法很简单,但是Activity是如何实现事务的管理的呢?我们先上一个简单的类图这个里面FragementManagerImpl持有mHost,一开始不知道是如何设置的,后来才发现是通过attachHost方法进行设置的。我们一步步去分析这个UML的视图是如何建立的从 getSupport...

weixin_39825722的博客 673

UML建模与软件开发设计(七)——时序图设计

UML建模与软件开发设计、类图、时序图等

流年梦里风起舞 2万+

android Fragment 生命周期 方法调用顺序

所以只要看执行结果中的日志,就可以知道 Fragment 的不同生命周期方法的执行顺序。,而这两个 Fragment 的生命周期方法都会打印日志。界面设计:点击左侧按钮,会将右侧 青色的。

wuyujin1997的博客 1027
上一篇: 如何应对Android面试官 -> Window 显示次序,尺寸计算
下一篇: 如何应对Android面试官 -> 玩转 MVx(MVC、MVP、MVVM、MVI)
老A说
博客等级 码龄14年 1181粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值