一、概述
本节主要分析下FragmentManager与FragmentTransaction的内部代码,了解一下当我们提交事务时,两者是怎么协调处理的
二、FragmentManager的介绍
关于FragmentManager的内容我们可以查看官网FragmentManager,当然更详细的我们也可以查看FragmentManager源码,在这里我就简单的介绍下,当我们在Activity中要获取FragmentManager时,我们直接调用的getFragmentManager()方法
FragmentManager fm = getFragmentManager();
如果你只想使用FragmentManager,那么这样一行代码就完全足够了,但是如果你想知其所以然,那么有一些地方就需要注意了,因为FragmentManager是一个抽象类,所以我们获取到的只是FragmentManager的一个实现类(子类FragmentManagerImpl)对象而已,具体的获取过程我们可以接着往下看,这是我们超类Activity类的部分代码
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*/
public FragmentManager getFragmentManager() {
return mFragments.getFragmentManager();
}
这是我们FragmentController类,我们发现其又调用了mHost.getFragmentManagerImpl()方法
private final FragmentHostCallback<?> mHost;
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
public FragmentManager getFragmentManager() {
return mHost.getFragmentManagerImpl();
}
这是我们的抽象类FragmentHostCallback< E >,通过对象组合,最后调用方法的返回值即一个FragmentManagerImpl对象
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}
而FragmentManagerImpl又何许东西也?这就是我们最后获取到的FragmentManagerImpl类,是一个内部类
public abstract class FragmentManager {
...//省略代码
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
...
}
...
}
知道了这些我们就明白了,其实我们平时所使用的findFragmentById都是FragmentManagerImpl的方法,多态嘛
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
/**注意只是根据需要展示了FragmentManagerImpl的部分代码*/
ArrayList<Fragment> mAdded;//管理着一个fragment队列
ArrayList<BackStackRecord> mBackStack;//管理着一个回退栈
@Override public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
//addFragment、removeFragment、hideFragment、showFragment
//detachFragment、attachFragment常用方法
public void addFragment(Fragment fragment, boolean moveToStateNow) {
//将fragment添加到容器里,并改变相应的标志位
...
}
//findFragmentById、findFragmentByTag常用方法
public Fragment findFragmentById(int id) {
//从容器里根据id取出相应的fragment
...
}
在这里我只是简单展示了一下FragmentManagerImpl的极少量代码,让我们心里先有个大致印象,当我们介绍事务FragmentTransaction的时候,我们会接触到FragmentManagerImpl更多的方法,明白当我们提交一个事务时,两者是怎么协调处理的。
三、FragmentTransaction的分析
上面我们说了FragmentManager,通过beginTransaction()方法,我们便能开启一个事务,之后就是我们的一些普通操作了
private void addFragment4() {
FragmentManager fm = getFragmentManager();
//在这里为了直观展示,就加一个局部变量
FragmentTransaction fragmentTransaction = fm.beginTransaction();
MyFragment4 fragment4 = (MyFragment4) fm.findFragmentById(R.id.activity5_fragment);
if(fragment4 == null){
fragment4 = new MyFragment4();
fragmentTransaction.add(R.id.activity5_fragment, fragment4)
//根据需要是否要加入到回退栈
.addToBackStack(null)
.commit();
}
}
我们知道,fm.beginTransaction()实际调用的是其子类FragmentManagerImpl的方法,其实就是个多态思想
@Override public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
通过官网FragmentTransaction我们可以知道,FragmentTransaction也是一个抽象类,我们所使用的事务即其子类BackStackRecord类,类中代码非常多,我们可以查看BackStackRecord源码,在这里,我就根据我们常用的add并commit的流程来简单介绍下BackStackRecord,并了解一下其与FragmentManagerImpl是怎么协调工作的,这是我们的BackStackRecord类
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable {
//在这里我们持有FragmentManagerImpl对象
//当然也就能根据需要调用FragmentManagerImpl方法了
final FragmentManagerImpl mManager;
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
}
这是我们的FragmentManagerImpl类,当我们在Activity中beginTransaction()时,我们知道我们创建了一个事务BackStackRecord,并将自身引用传递了过去
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
/**注意只是根据需要展示了FragmentManagerImpl的部分代码*/
ArrayList<Fragment> mAdded;//管理着一个fragment队列
@Override public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
}
之后我们会调用BackStackRecord类的add(int var1, Fragment var2)方法
public FragmentTransaction add(int containerViewId, Fragment fragment) {
//doAddOp(...)这是一个私有方法
//在方法里会创建一个Op对象
//Op对象的作用就是记录一次操作的动作和Fragment引用以及操作使用的动画
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
之后我们接着调用BackStackRecord类的addToBackStack(null)加入回退栈方法
public FragmentTransaction addToBackStack(String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException("This FragmentTransaction is not allowed to be added to the back stack.")
}
//我们发现其实这个方法只是改变了标志位,并没有实际的逻辑代码
//这也是我们为什么必须在commit之前加入回退栈的原因
//因为commit之后加入,没有改变标志位的事务就不会被提交
mAddToBackStack = true;
mName = name;
return this;
}
之后我们接着在BackStackRecord类中调用commit()方法,提交我们的本次的事务
public int commit() {
return commitInternal(false);
}
//如果提交时,生命周期处于Saving Activity之后
//那么使用commit就会由于丢失信息从而抛出错误
//如果不需要保存信息,可以使用commitAllowingStateLoss
public int commitAllowingStateLoss() {
return commitInternal(true);
}
//在这里我们就简单看下allowStateLoss为false的情况
int commitInternal(boolean allowStateLoss) {
...//省略部分代码
if (mAddToBackStack) {
//使用mAvailBackStackIndices和mBackStackIndices两个数组
//来为BackStackRecord分配Index
mIndex = mManager.allocBackStackIndex(this);
} else {
Index = -1;
}
//这是我们最后提交的方法,会调用FragmentManagerImpl类的enqueueAction方法
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
那我们接下来就看下FragmentManagerImpl类的allocBackStackIndex(…)方法,当加入返回栈并在commit事务之前
// Must be accessed while locked.
ArrayList<BackStackRecord> mBackStackIndices;
ArrayList<Integer> mAvailBackStackIndices;
public int allocBackStackIndex(BackStackRecord bse) {
synchronized (this) {
if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
if (mBackStackIndices == null) {
mBackStackIndices = new ArrayList<BackStackRecord>();
}
int index = mBackStackIndices.size();
mBackStackIndices.add(bse);
return index;
} else {
int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
mBackStackIndices.set(index, bse);
return index;
}
}
}
这是我们最后commit提交后调用的FragmentManagerImpl类的enqueueAction(…)方法
ArrayList<Runnable> mPendingActions;//每提交一个事务都在不同线程里
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
//这个方法我就不细写了,其主要作用
//遍历mPendingActions管理的事务线程
//并调用每个线程事务(BackStackRecord)类的run方法
//随后一个个移除相应的事务线程
execPendingActions();
}
};
public void enqueueAction(Runnable action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
//这是管理事务的线程集合,每个线程即代表着一个待处理的事务操作
mPendingActions = new ArrayList<Runnable>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
//mHost.getHandler()返回一个handler对象
//即handler.post(Runnable action)
//所以会调用mExecCommit的run方法
mHost.getHandler().post(mExecCommit);
}
}
}
这就是我们的BackStackRecord类的run方法,在这里我们根据Op对象所携带的信息,判断进行哪种操作,随后再调用FragmentManagerImpl的方法,moveToState(…)和是否需要将事务添加到回退栈
public void run() {
...
//根据OP的信息调用相应的操作,例如当我们add操作
switch (op.cmd) {
case OP_ADD:
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
//将当前操作的fragment添加到FragmentManager管理的列表中
mManager.addFragment(f, false);
break;
case OP_REMOVE:
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
break;
...
}
...
mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true);
if (mAddToBackStack) {
//将本次事务添加到回退栈
mManager.addBackStackState(this);
}
}
那么最后我们再接着回来看下FragmentManagerImpl类的部分方法
public void addFragment(Fragment fragment, boolean moveToStateNow) {
//将fragment添加到管理队列中,并改变相应的标志位
...
}
//在回退栈中添加一个事务BackStackRecord
void addBackStackState(BackStackRecord state) {
if (mBackStack == null) {
mBackStack = new ArrayList<BackStackRecord>();
}
mBackStack.add(state);
//回调onBackStackChanged
reportBackStackChanged();
}
//这个方法非常重要,每当Fragment的生命周期中状态改变,都会被调用
//这也保证了Fragment与Activity能够保持同步
//具体的代码,感兴趣的可以查看源码了解下
void moveToState(int newState, int transit, int transitStyle, boolean always) {
//Fragment的状态切换的操作逻辑
...
}
到这里分析就已经结束了,开启并提交一个事务,是否将事务添加到返回栈两种情况,我们合二为一的做了介绍,下面我们再来看一下,当我们按返回键时,当有事务在返回栈的情况下,事务是怎么被弹出栈的,这是我们Activity的代码
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
//如果我们Fragment的事务回退栈还有事务能被弹出则返回true,否则返回false
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
//经过一些其他条件的判断,最终会调用finish()方法
finishAfterTransition();
}
}
下面我们来接着看下FragmentManagerImpl类的popBackStackImmediate(…)方法
@Override public boolean popBackStackImmediate() {
checkStateLoss();
//如果存在待处理的事务,则直接返回true
executePendingTransactions();
//参数是固定的,注释看下面
return popBackStackState(mHost.getHandler(), null, -1, 0);
}
这是FragmentManagerImpl类的popBackStackState(…)方法
//1往左移0位,实际还是1,并且0&1=0 (按位与)
public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
boolean popBackStackState(Handler handler, String name, int id, int flags) {
//如果我们的回退栈为null,那么直接返回false退出Activity
if (mBackStack == null) {
return false;
}
//当返回键的时候,传参是固定的,所以直接走这个分支
if(if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0)) {
int last = mBackStack.size()-1;
if (last < 0) {
return false;
}
//将我们管理的回退栈最顶层的remove掉
final BackStackRecord bss = mBackStack.remove(last);
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
//作用是循环所有Op,找到第一个被删除的fragment
//和最后一个被添加的fragment
bss.calculateBackFragments(firstOutFragments, lastInFragments);
//这是主要方法,注释看下面
bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
//FragmentManagerImpl管理着一个ArrayList<OnBackStackChangedListener> 集合
//这个方法作用便是循环遍历onBackStackChanged()方法
reportBackStackChanged();
}else {
...
}
}
这是我们需要的BackStackRecord类的popFromBackStack(…)方法
public TransitionState popFromBackStack(boolean doStateMove, TransitionState state
, SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
...
//根据事务的Op携带的信息,知道事务回退栈里的事务是什么操作,例如add
//知道栈里的事务是的类型了,当然back时候就知道怎么相应处理了
//例如事务A是add而来,那么back后执行remove;
//如果事务A是replace而来,那么back后执行先remove掉新的后再add进替换掉那个old的
Op op = mTail;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.popExitAnim;
//因为回退栈里的事务里Op标识说明这是添加操作
//所以本次back键直接将这个事务removeFragment即可
mManager.removeFragment(f
, FragmentManagerImpl.reverseTransit(mTransition)
, mTransitionStyle);
}
break;
...//其他操作情况
}
}
...
}
四、总结
本节主要简单分析了一下我们在添加事务时的具体实现流程,如果想要查看更多Fragment的基础知识,去我的博客目录里查看吧,因为关于每块知识点的介绍,博客单节写的比较零散,不容易查找