Fragment FragmentManager FragmentTransaction源码浅析

Fragment相关类的关系及说明

UML类图


上图虽然不是Fragment工作过程中所有类,但是也能表达Fragment工作过程中主要类的关系。下面对一些类进行简要的说明。

相关类说明

  • HostCallbacksFragmentActivity内部类,继承FragmentHostCallback,在其相应方法中调用FragmentActivity的相应方法,实现其功能。实例化FragmentController时传入。
  • FragmentControllerFragmentActivity主要是通过它来对Fragment进行相应的操作。FragmentController利用FragmentActivity实现的FragmentHostCallback获取FragmentManagerImpl,提供Fragment生命周期分发方法。
  • FragmentHostCallback<E>:提供Fragment一些回调方法实现,持有宿主Activity的引用,持有FragmentManagerImpl实例。
  • FragmentManagerImplFragmentManager具体实现,并且实现了LayoutInflater.Factory接口。管理宿主中的所有Fragment
  • BackStackRecord:继承FragmentTransaction,提供事务操作及事务相关操作的记录,在进行返回栈操作时便于事务的恢复。
  • OpBackStackRecord内部类,用于存储Fragment操作类型及进出动画。

Fragment生命周期

想要了解Fragment生命周期,当然是进入FragmentActivity了,因为Fragment生命周期和Activity生命周期息息相关嘛。

进入FragmentActivity直接搜索Fragment,首先我们可以找到一个叫mFragments的常量:

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

再接着搜索,可以在FragmentActivity相关生命周期方法中找到mFragments的使用:

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        mFragments.dispatchCreate();
    }
    ...// 这里只展示一个,其他生命周期方法类同

至此,我们可以知道Fragment的生命周期为什么和Activity生命周期息息相关了。接着我们再看看mFragments也就是FragmentController中相关方法:

private final FragmentHostCallback<?> mHost;
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
        return new FragmentController(callbacks);
    }

    private FragmentController(FragmentHostCallback<?> callbacks) {
        mHost = callbacks;
    }

public void dispatchStart() {
        mHost.mFragmentManager.dispatchStart();
    }

FragmentController相关方法其内部调用的FragmentManager的方法,跟踪代码发现,首先会进入moveToState(int newState, boolean always)方法中,在其中会遍历所以已添加和处于活动中的Fragment进行下一步处理:

void moveToState(int newState, boolean always) {
        ...

        if (mActive != null) {
            boolean loadersRunning = false;

            // Must add them in the proper order. mActive fragments may be out of order
            final int numAdded = mAdded.size();
            for (int i = 0; i < numAdded; i++) {
                Fragment f = mAdded.get(i);
                moveFragmentToExpectedState(f);
                if (f.mLoaderManager != null) {
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                }
            }

            // Now iterate through all active fragments. These will include those that are removed
            // and detached.
            final int numActive = mActive.size();
            for (int i = 0; i < numActive; i++) {
                Fragment f = mActive.valueAt(i);
                if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                    moveFragmentToExpectedState(f);
                    if (f.mLoaderManager != null) {
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                    }
                }
            }

            if (!loadersRunning) {
                startPendingDeferredFragments();
            }

            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
                mHost.onSupportInvalidateOptionsMenu();
                mNeedMenuInvalidate = false;
            }
        }
    }

然后进入moveFragmentToExpectedState()方法中,首先会进入moveToState(Fragment,newState,transit,transitionStyle,keepActive)方法中进行状态分发,根据不同的状态进行处理相应的逻辑,例如在Create状态将View添加到ActivityViewGroup中等;然后进行View的移动,确保FragmentView以正确的顺序显示;最后执行动画:

void moveFragmentToExpectedState(Fragment f) {
        if (f == null) {
            return;
        }
        int nextState = mCurState;
        if (f.mRemoving) {
            if (f.isInBackStack()) {
                nextState = Math.min(nextState, Fragment.CREATED);
            } else {
                nextState = Math.min(nextState, Fragment.INITIALIZING);
            }
        }
        // 第一步:根据不同状态进行分发
        moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);

        if (f.mView != null) {
            // 第二步:移动View在Activity的ViewGroup中的显示顺序
            // Move the view if it is out of order
            Fragment underFragment = 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);
                }
            }
            // 第三步:新添加的Fragment,执行动画
            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:
                AnimationOrAnimator anim = loadAnimation(f, f.getNextTransition(), true,
                        f.getNextTransitionStyle());
                if (anim != null) {
                    setHWLayerAnimListenerIfAlpha(f.mView, anim);
                    if (anim.animation != null) {
                        f.mView.startAnimation(anim.animation);
                    } else {
                        anim.animator.setTarget(f.mView);
                        anim.animator.start();
                    }
                }
            }
        }
        // 第四步:判断Fragment显示隐藏是否改变,如改变,则在completeShowHideFragment中执行动画
        if (f.mHiddenChanged) {
            completeShowHideFragment(f);
        }
    }

以上是Activity生命周期触发Fragment生命周期的过程,至于动态添加Fragment,实际上最终也是到moveToState(Fragment,newState,transit,transitionStyle,keepActive)中根据状态进行处理。

Fragment事务

在开发中,我们通常都是使用事务来操作Fragment的添加、显示、隐藏的,那么其内部是如何处理的呢?

首先,我们来看下add()hide()show()replace()方法中是如何处理的。进入BackStackRecord类查看代码发现,它们都调用了doAddOp()方法:

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
        ...// 省略其他内容
        addOp(new Op(opcmd, fragment));
    }

doAddOp()方法最终会创建一个Op()对象,并添加到集合中保存。Op类我们在开始的时候说过,主要是用来存储Fragment操作类型的,也就是cmd,它的可选参数有:

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;

通过上面查看代码,我们可以发现:开启事务后我们进行的add()hide()等操作都会以Op()对象的形式存储在集合中。接下来我们看看最后我们所调用的commit()又做了些什么?

查看commit()方法发现其调用的是commitInternal()方法:

int commitInternal(boolean allowStateLoss) {
        ...//省略部分代码
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

在其中调用的是FragmentManagerenqueueAction()方法,会将当前BackStackRecord实例传入其中:

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                if (allowStateLoss) {
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                }
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<>();
            }
            mPendingActions.add(action);
            scheduleCommit();
        }
    }

enqueueAction方法中,将action排入队列,最后调用scheduleCommit()方法:

private void scheduleCommit() {
        synchronized (this) {
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
            if (postponeReady || pendingReady) {
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
            }
        }
    }

Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            execPendingActions();
        }
    };

查看代码发现,最后调用的是FragmentHostCallbackHandler进行异步操作,此Handler实际上是FragmentActivity的。

跟踪代码发现execPendingActions()方法最后会调用BackStackRecordexecutePopOps()executeOps()方法来处理具体的操作:

    void executePopOps(boolean moveToState) {
        for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
            final Op op = mOps.get(opNum);
            Fragment f = op.fragment;
            if (f != null) {
                f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
                        mTransitionStyle);
            }
            //根据Op类型,调用FragmentManager相关方法,改变Fragment状态
            switch (op.cmd) {
                case OP_ADD:
                    f.setNextAnim(op.popExitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.popEnterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.popEnterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.popExitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.popEnterAnim);
                    mManager.attachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.popExitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_SET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(null);
                    break;
                case OP_UNSET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(f);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
            if (!mReorderingAllowed && op.cmd != OP_REMOVE && f != null) {
            // 上面讲生命周期的时候有相应描述
                mManager.moveFragmentToExpectedState(f);
            }
        }
        if (!mReorderingAllowed && moveToState) {
           // 上面讲生命周期的时候有相应描述
            mManager.moveToState(mManager.mCurState, true);
        }
    }

总结

Fragment相关代码较多,以上也只是一点粗陋的分析,接下来的路还很漫长。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值