Fragment FragmentManager Fragmen
Fragment相关类的关系及说明
UML类图
UML类关系图上图虽然不是
Fragment
工作过程中所有类,但是也能表达Fragment
工作过程中主要类的关系。下面对一些类进行简要的说明。
相关类说明
-
HostCallbacks
:FragmentActivity
内部类,继承FragmentHostCallback
,在其相应方法中调用FragmentActivity
的相应方法,实现其功能。实例化FragmentController
时传入。 -
FragmentController
:FragmentActivity
主要是通过它来对Fragment
进行相应的操作。FragmentController
利用FragmentActivity
实现的FragmentHostCallback
获取FragmentManagerImpl
,提供Fragment
生命周期分发方法。 -
FragmentHostCallback<E>
:提供Fragment
一些回调方法实现,持有宿主Activity
的引用,持有FragmentManagerImpl
实例。 -
FragmentManagerImpl
:FragmentManager
具体实现,并且实现了LayoutInflater.Factory
接口。管理宿主中的所有Fragment
。 -
BackStackRecord
:继承FragmentTransaction
,提供事务操作及事务相关操作的记录,在进行返回栈操作时便于事务的恢复。 -
Op
:BackStackRecord
内部类,用于存储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
添加到Activity
的ViewGroup
中等;然后进行View
的移动,确保Fragment
的View
以正确的顺序显示;最后执行动画:
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;
}
在其中调用的是FragmentManager
的enqueueAction()
方法,会将当前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();
}
};
查看代码发现,最后调用的是FragmentHostCallback
的Handler
进行异步操作,此Handler
实际上是FragmentActivity
的。
跟踪代码发现execPendingActions()
方法最后会调用BackStackRecord
的executePopOps()
或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
相关代码较多,以上也只是一点粗陋的分析,接下来的路还很漫长。