自动Android在3.0版本中退出Fragment以来,fragment在我们日常的开发中无处不在,他使我们的在开发android时能更好的做到view的解耦。关于Fragment的用法,相信大家已经用的滚瓜烂熟了,各种FragmentTransaction的操作,都信手拈来。今天我们要从源码的角度去剖析fragment内部实现的原理,我相信只有了解了内部实现原理,我们在碰到fragment的issue的时候才知道如何去解决。
我们今天要分析的是support v4包中的Fragment,相信绝大部分人都是用的兼容包中的fragment。
先上一张图:
Fragment有关类结构图这张图描述的是与fragment相关的类的UML图,基本描述了这些类之间的关系。
Fragment理论上可以被任何对象持有,然后管理其生命周期,但是绝大部分时候,我们都是在activity里面使用它,我们可以从Activity出发,理清楚这些类之间的关系。
FragmentActivity
兼容包中,支持fragment的activity叫做FragmentActivity, 我们常用的AppCompatActivity也是继承自它,
在FragmentActivity中有一个重要的成员变量mFragments,它的类型是FragmentController
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
正是这个mFragments的存在使得在FragmentActivity中进行fragment操作成为可能,我们可以看到在FragmentActivity中进行的任何fragment的操作都得经FragmentController之手
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
//...
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
//...
mFragments.dispatchCreate();
}
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
因此,我们进到FragmentController类中去一探究竟。打开FragmentController,发现其函数实现非常简单。基本上你可以认为FragmentController是FragmentManager的代理,Activity需要的FragmentController的函数,最后调用的都是FragmentHostCallback中的FragmentManager的方法。
FragmentHostCallback,我们可以认为他是用来管理Fragment生命周期,同时作为代理提供fragment需要与外界打交道时的函数实现的比如从fragment中启动新的Activity, 请求权限等等。其Fragment生命周期的的管理由FragmentManager负责,其余部分代理功能由其自己负责。
我们打开FragmentHostCallback的源代码,可以看到其头顶注释中写着:fragment可以被任何对象持有,要使一个对象具有持有和管理fragment生命周期的能力,我们只需要实现FragmentHostCallback中的函数。显然,我们最常见的FragmentActivity肯定实现了FragmentHostCallback,我们跳转到FragmentActivity,看到其内部有一个非静态内部类HostCallbacks, 正式这个内部类的存在,使得FragmentActivity具有了持有和管理Fragment的能力,Fragment与外部交互的功能都由FragmentActivity实现了。至于FragmentController,前面已经说到,只是作为中间桥梁的作用。
Fragment
前面讲了这么多,我们还没有开始介绍今天的主角Fragment, 接下来我们就来揭开其稍许神秘的面纱。
Fragment = Attr + View + + State, 此处等待UML图
Attr
Attr指得是Fragment的一些固有属性,不会随着Fragment的生命周期发生变化的,比如
Bundle mArguments; //构造参数
boolean mFromLayout; //是否从layout文件中创建
...
View
View是Fragment创建出来并显示给用户的界面的view,如果Fragment被持有,会被添加到Activity某一块layout中去
// The parent container of the fragment after dynamically added to UI.
ViewGroup mContainer;
// The View generated for this fragment.
View mView;
// The real inner view that will save/restore state.
View mInnerView;
State
State指的是Fragment在生命周期变迁中中会发生改变的状态
int mState = INITIALIZING; //生命周期状态
boolean mAdded; //是否被添加
boolean mRemoving; //是否被移除
boolean mHidden;// 是否被隐藏
boolean mDetached; //是否已经分离
...
其中Fragment的成员变量mState,直接映射了Fragment的生命周期状态变迁,其取值状态在以下常量中:
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
我们在开中经常重写的onCreate, onResume, onStop方法都发生mState的变迁过程中。 接下来,我们就来看看Fragment的生命周期是如何变化的。
Fragment事务操作:BackStackRecord
我们在开发中,每次要操作那个Fragment的添加,删除,隐藏,显示等,都需要使用FragmentTransaction,比如添加一个Fragment:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.contaniner, testFragment);
transaction.commit();
FragmentTransaction实际上是一个抽象类,里面定义了一些关于Fragment操作的函数接口,
public abstract class FragmentTransaction {
add
replace
remove
hide
show
detach
attach
addToBackStack
...
}
从FragmentManger.beginTransaction真正返回的确是一个BackStackRecord类, 其实现了FragmentTransaction所定义的接口。
接下来,我们以添加为例,看看BackStackRecord是如何完成Add这个transaction的。
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
BackStackRecord中实现的四个add函数,最后都调用了doAddOp,我们注意到已经添加过的Fragment其tag和被添加到的containerId是不能更改的,否则会抛异常。 函数最后new了一个Op,Op是啥?Op其实就是Operation的简称,有经验的读者应该知道在一次FragmentTransaction中实际上可以进行多次add,remove之类的操作。每次操作,都会生成一个新的Op对象,在transaction commit操作时,会将这些Operation全部执行掉。
我们来看看Op类对象里都有些啥
static final class Op {
Op next;
Op prev;
int cmd;
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
ArrayList<Fragment> removed;
}
从next, prev 两个指针可以看出,Op是作为一个链表的节点而存在的,因此FragmentTransaction肯定是在一个链表中存储了一次事务中的所有需要执行的操作。
cmd定义了Operation操作的类型
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;
fragment指定了这次Operation要操纵哪一个Fragment
此外Op类还包含了转场动画和一个操作会移除的Fragment集合。
doAddOp函数最后执行了
void addOp(Op op) {
if (mHead == null) {
mHead = mTail = op;
} else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
mNumOp++;
}
addOp执行了一个典型的添加节点到链表末尾的数据结构操作,并将transaction的动画赋给op,最后讲mNumOp加一,mNumOp代表了这次transaction中包含的操作个数。如果为0,则isEmpty返回true.
等到操作都添加好了之后,就差commit了。
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
}
mCommitted = true;
if (mAddToBackStack) {
//添加到返回栈
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
如果设置了addToBackStack,就会执行添加到返回栈的操作,这个我们后面会专门讲,mManager.enqueueAction 顾名思义就是讲当前的transaction操做入队列,因此在FragmentManager肯定会维护一个队列来存储当前尚未执行的transaction.
public void enqueueAction(Runnable action, boolean allowStateLoss) {
...
synchronized (this) {
...
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
enqueueAction首先会将action,添加到一个叫mPendingAction的列表中去,这个列表中存储着一堆Runnable对象,代表着还未执行的事务,稍等一会儿,我们刚刚说到的是BackStackRecord类对吧,怎么可以添加到Runnable列表中呢,原来BackStackRecod本身还是实现了Runnabled接口,是一个可以执行的对象。添加完毕之后,会调用FragmentHostCallback中提供的getHandler方法,获取到Handler方法,然后向主线程的MessageQueue中发送一个mExecCommit可执行对象
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
public boolean execPendingActions() {
boolean didSomething = false;
while (true) {
int numActions;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
}
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
//讲mPendingAction中的对象转移到mTmpActions
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
//遍历mTmpActions,执行run
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
}
...
return didSomething;
}
因此绕来绕去,最后调用的BackStackRecord本身的run方法,这也符合了commit方法名字本身的定义,transaction只是被批量提交到了主线程的任务队列里,并不是马上执行,等待主线程的looper去安排这些任务的执行。
那好,我们现在回家吧,去看看BackStackRecord。
public void run() {
...
Op op = mHead;
while (op != null) {
int enterAnim = state != null ? 0 : op.enterAnim;
int exitAnim = state != null ? 0 : op.exitAnim;
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = enterAnim;
mManager.addFragment(f, false);
} break;
case OP_REPLACE: {
...
} break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = exitAnim;
mManager.removeFragment(f, transition, transitionStyle);
} break;
case OP_HIDE: {
...
} break;
...
//更多case
}
op = op.next;
}
//将active状态的fragment全部执行状态变迁检查
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
run方法内部根据不同的cmd走了很不不同的分支,每个分支内部都会对,fragment状态做改变,最后调用moveToState将fragment的生命周期状态mState进行变迁。
当然我们注意到hide和show,它们内部实际上不会调用调用moveToState, 因为hideFragment实际上就做了三件事请,
- 设置mHidden 为true
- fragment.mView.setVisibility(View.GONE); 隐藏fragment的view
- fragment.onHiddenChanged(true); 调用onHiddenChange
showFragment也是类似,只不过行为正好相反。
public void addFragment(Fragment fragment, boolean moveToStateNow) {
...
makeActive(fragment);
if (!fragment.mDetached) {
...
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) {
moveToState(fragment);
}
}
}
void makeActive(Fragment f) {
if (f.mIndex >= 0) {
return;
}
if (mAvailIndices == null || mAvailIndices.size() <= 0) {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
f.setIndex(mActive.size(), mParent);
mActive.add(f);
} else {
f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f);
}
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}
addFragment会将fragment添加到 mAdded和 mActive这两个集合当中,这两个集合维护了当前activity中维护的已经添加的fragment列表和当前处于活跃状态的fragment列表,如果fragment位于mActive中,那么当activity的状态发生变化时,fragment也会跟随着发生变化。FragmentManger 如何引导fragment的状态发生变化呢?
这一切都发生在moveToState函数当中
Fragment状态变迁:moveToState
Fragment状态变迁发生在用户主动发起transaction,或者fragment被add到activity之后跟随activity的生命周期变化一起发生改变。每次状态变迁最终都会走到函数moveToState,字面意思是将fragment迁移到新的状态
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
...
if (f.mState < newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
...
switch (f.mState) {
case Fragment.INITIALIZING:
...
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
...
}
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.performResume();
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
f.performPause();
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.performStop();
}
case Fragment.STOPPED:
if (newState < Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
f.performReallyStop();
}
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
...
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
...
}
}
}
...
}
fragment的state取值,为前面提到的七中状态,其中最低值是INITIALIZING状态,代表fragment刚创建,还未被add, 最高状态值是RESUMED,代表fragment处于前台。 所以moveToState内部分两条线,状态跃升,和状态降低,里面各有一个switch判断,注意到switch里每个case都没有break,这意味着,状态可以持续变迁,比如从INITIALIZING,一直跃升到RESUMED,将每个case都走一遍,每次case语句内,都会改变state的值。
Fragment状态变迁图比如我们常见的add操作,最后调用的是
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);
就是将fragment迁移到FragmentManager当前的状态,因为我们不知道用户什么时候add fragment,因此fragment被add之后,就将其状态迁移到FragmentManager当前的状态,然后跟随FragmentManager一起发生状态变迁,除非用户手动removeFragment将其从mActive列表中移除。
public void dispatchCreate() {
mStateSaved = false;
moveToState(Fragment.CREATED, false);
}
public void dispatchActivityCreated() {
mStateSaved = false;
moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchStart() {
mStateSaved = false;
moveToState(Fragment.STARTED, false);
}
public void dispatchResume() {
mStateSaved = false;
moveToState(Fragment.RESUMED, false);
}
public void dispatchPause() {
moveToState(Fragment.STARTED, false);
}
public void dispatchStop() {
// See saveAllState() for the explanation of this. We do this for
// all platform versions, to keep our behavior more consistent between
// them.
mStateSaved = true;
moveToState(Fragment.STOPPED, false);
}
public void dispatchReallyStop() {
moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchDestroyView() {
moveToState(Fragment.CREATED, false);
}
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
moveToState(Fragment.INITIALIZING, false);
mHost = null;
mContainer = null;
mParent = null;
}
这些 dispatchxxx函数由FragmentActivity状态变化引发,然后调用moveToState将处于mActive集合中的fragment的状态全部变更一次。
比如,当FragmentActivity pause的时候,其会通过FM
通知framgents进行状态变迁。
/**
* Dispatch onPause() to fragments.
*/
@Override
protected void onPause() {
super.onPause();
mResumed = false;
if (mHandler.hasMessages(MSG_RESUME_PENDING)) {
mHandler.removeMessages(MSG_RESUME_PENDING);
onResumeFragments();
}
mFragments.dispatchPause();
}
Fragment状态的保存
既然Fragment持有view,以及一些状态属性,那么在Activity保存自身状态以便下次恢复的时候,就需要把fragment的状态也保存起来,这样activity被系统finish掉,然后重新创建时就能恢复上次的fragment状态。那我们首先直奔FragmentActivity的onSaveInstanceState函数:
/**
* Save all appropriate fragment state.
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//调用FragmentController 代理FragmentManager 保存状态
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
//保存跟fragment启动activity等待result的状态
if (mPendingFragmentActivityResults.size() > 0) {
outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);
int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
}
outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
}
}
saveAllState函数就会将FragmentManager在重新恢复fragmentstate时需要的所有信息保存起来,小伙伴们可以跟进去看,我在这里画了张图:
FragmentManager状态的保存关于返回栈的保存没有详细标注,不过我们后面会再详细讲到。
Fragment 状态的恢复
Fragment状态的恢复其实就是保存状态的逆过程,不过,额外的工作是,我们需要根据之前保存的每个active的fragmentstate来恢复创建Fragment:
public Fragment instantiate(FragmentHostCallback host, Fragment parent) {
if (mInstance != null) {
return mInstance;
}
final Context context = host.getContext();
if (mArguments != null) {
mArguments.setClassLoader(context.getClassLoader());
}
//利用保存的状态恢复fragment
mInstance = Fragment.instantiate(context, mClassName, mArguments);
if (mSavedFragmentState != null) {
mSavedFragmentState.setClassLoader(context.getClassLoader());
mInstance.mSavedFragmentState = mSavedFragmentState;
}
mInstance.setIndex(mIndex, parent);
mInstance.mFromLayout = mFromLayout;
mInstance.mRestored = true;
mInstance.mFragmentId = mFragmentId;
mInstance.mContainerId = mContainerId;
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
mInstance.mDetached = mDetached;
mInstance.mFragmentManager = host.mFragmentManager;
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
"Instantiated fragment " + mInstance);
return mInstance;
}
其中构造Fragment的代码如下:
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
try {
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = context.getClassLoader().loadClass(fname);
sClassMap.put(fname, clazz);
}
Fragment f = (Fragment)clazz.newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.mArguments = args;
}
return f;
} catch (ClassNotFoundException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (java.lang.InstantiationException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (IllegalAccessException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
}
}
是不是发现这段代码灰常熟悉,很多人恐怕都遇到过代码中描述的异常。因为Fragment在恢复时,是利用反射的方式去创建,首先利用类加载器去加载类,然后调用其pubic empty 构造函数去创建fragment。
所以如果Fragment不是public的,或者fragment没有public的无参构造函数,那么你的应用肯定会碰到这些异常,只不过你在调试的时候可能无法发现,因为你的手机环境太好,构不成saveInstanceState然后恢复它们的条件。
如果我们用Android studio 模板去创建fragment,那么他会给我们默认实现一个newInstance的静态构造函数,并把构造参数写在argument里,因为前面那张图里可以看到,argument会在保存fragment状态时保存起来的。另外不要写任何带参数的构造函数,因为这样子,默认构造函数就会被隐藏,除非你手动去实现它。 话说这个instantiate是个public方法,因此你也可以直接调用这个函数去创建fragment,只不过它使用起来不是那么方便,使用者不知道我们需要往里面传什么参数。
MyFragment.instantiate(activity, MyFragment.getClass().getName(), args)
臭名昭著的 “Can not perform this action after onSaveInstanceState”
这里不得不提一提开发中经常会碰到的一个异常,异常抛出时的message为:“Can not perform this action after onSaveInstanceState”, 意为,FragmentTransaction不能再onSaveInstanceState后提交,为什么会抛出这样一个异常呢,因为FragmentManager认为在onSaveInstanceState 发生之后提交的transaction不能在下次Fm恢复时得到恢复,继而认为这样做是危险的,拒绝提交,除非你指定了allowStateLoss,即允许状态的丢失。
开发者只需要用commitAllowingStateLoss,即可以成功提交这样的transaction,即使它有可能会丢失状态。
Fragment返回栈
使用fragmentTransaction的时候可以将其加入返回栈,这样用户就可以有机会去撤销这一动作,将其从返回栈中pop出来。
public FragmentTransaction addToBackStack(String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
//标记 即将加入返回栈
mAddToBackStack = true;
//标记在返回栈中的名字
mName = name;
return this;
}
//transaction提交
public void run() {
//...
//加入到FragmentManager的返回栈中
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
//FragmentManager添加返回栈
void addBackStackState(BackStackRecord state) {
if (mBackStack == null) {
mBackStack = new ArrayList<BackStackRecord>();
}
mBackStack.add(state);
//通知返回栈监听者们发生改变
reportBackStackChanged();
}
FragmentManager中有一个叫做mBackStack的列表,保存了添加到返回栈的所有record, 当用户选择popBackStack的时候,就可以将其pop出来。
我们常用的pop操作就是popBackStack函数,其实FM还提供了很多pop操作,它可以指定以name和id指定pop哪个record,还可以指定flag:POP_BACK_STACK_INCLUSIVE, 如果指定了这个flag就表示将name或者id相等且连续的record全部pop出来。这些操作最后都调用了函数
boolean popBackStackState(Handler handler, String name, int id, int flags) {
//如果返回栈不存在,立即返回
if (mBackStack == null) {
return false;
}
//如果name、id、POP_BACK_STACK_INCLUSIVE全部都没有设置,直接移除栈顶的一个record
if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
int last = mBackStack.size()-1;
if (last < 0) {
return false;
}
final BackStackRecord bss = mBackStack.remove(last);
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
bss.calculateBackFragments(firstOutFragments, lastInFragments);
bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
reportBackStackChanged();
} else {
int index = -1;
if (name != null || id >= 0) {
//从栈顶开始寻找一个name或者id匹配的record,找到即跳出循环
index = mBackStack.size()-1;
while (index >= 0) {
BackStackRecord bss = mBackStack.get(index);
if (name != null && name.equals(bss.getName())) {
break;
}
if (id >= 0 && id == bss.mIndex) {
break;
}
index--;
}
//如果没找到,函数返回
if (index < 0) {
return false;
}
//如果设置了POP_BACK_STACK_INCLUSIVE,则向栈底方向寻找连续匹配的record
if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
index--;
// Consume all following entries that match.
while (index >= 0) {
BackStackRecord bss = mBackStack.get(index);
if ((name != null && name.equals(bss.getName()))
|| (id >= 0 && id == bss.mIndex)) {
index--;
continue;
}
break;
}
}
}
if (index == mBackStack.size()-1) {
return false;
}
//弹出从栈顶到连续相同匹配的record记录位置的所有record,加入集合states中
final ArrayList<BackStackRecord> states
= new ArrayList<BackStackRecord>();
for (int i=mBackStack.size()-1; i>index; i--) {
states.add(mBackStack.remove(i));
}
final int LAST = states.size()-1;
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
//计算在连续record中,最先remove的fragment集合 和 最后进入的fragment集合
for (int i=0; i<=LAST; i++) {
states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
}
BackStackRecord.TransitionState state = null;
//对这些record列表执行逆操作
for (int i=0; i<=LAST; i++) {
if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
state = states.get(i).popFromBackStack(i == LAST, state,
firstOutFragments, lastInFragments);
}
//通知返回栈监听器更新
reportBackStackChanged();
}
return true;
}
其中比较复杂的两步,一步是calculateBackFragments, 还有一个是popFromBackStack,我们先看calculateBackFragments:
为什么需要计算calculateBackFragments? 其实是因为涉及到动画的方面,在一次在一次transaction中可能会移除和添加多次fragments,这样动画的编排就必须按顺序来,这次分析中,我们就不对动画做过多分析了,因为这是相对来说次要点的知识点。所以我们集中关心BackStackRecord 的popFromBackStack函数
public TransitionState popFromBackStack(boolean doStateMove, TransitionState state,
SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
//...动画相关
int transitionStyle = state != null ? 0 : mTransitionStyle;
int transition = state != null ? 0 : mTransition;
Op op = mTail;
while (op != null) {
int popEnterAnim = state != null ? 0 : op.popEnterAnim;
int popExitAnim= state != null ? 0 : op.popExitAnim;
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(transition), transitionStyle);
} break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (f != null) {
f.mNextAnim = popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(transition), transitionStyle);
}
if (op.removed != null) {
for (int i=0; i<op.removed.size(); i++) {
Fragment old = op.removed.get(i);
old.mNextAnim = popEnterAnim;
mManager.addFragment(old, false);
}
}
} break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = popEnterAnim;
mManager.addFragment(f, false);
} break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = popEnterAnim;
mManager.showFragment(f,
FragmentManagerImpl.reverseTransit(transition), transitionStyle);
} break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = popExitAnim;
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(transition), transitionStyle);
} break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = popEnterAnim;
mManager.attachFragment(f,
FragmentManagerImpl.reverseTransit(transition), transitionStyle);
} break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = popEnterAnim;
mManager.detachFragment(f,
FragmentManagerImpl.reverseTransit(transition), transitionStyle);
} break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.prev;
}
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(transition), transitionStyle, true);
state = null;
}
if (mIndex >= 0) {
mManager.freeBackStackIndex(mIndex);
mIndex = -1;
}
return state;
}
基本上从多个switch-case分支语句里就可以看出pop执行的就是commit的反操作,因为因为transaction都是成对存在的
- add <-> remove
- attach <-> detach
- show <-> hide
- replace( remove x n + add x m) <-> replace ( remove x m + add x n)
返回栈的状态的保存
返回栈状态的保存,相当于要把整个BackStackRecord的列表保存下来,以便下次恢复,前面提到BackStackRecord,可以跟 BackStackState这个parcelable映射起来。基本上BackStackRecord都是可以parcel的类型,出了Op链表,Op链表映射为BackStackState的int[] mOps;
看完了返回栈,基本上有关Fragment的核心知识点都了解的差不多了,当然我们也跳过了一些知识点,比如有关动画的部分、ChildFragmentManager等。但基本上Fragment在使用到遇到问题的部分,都可以从上面的分析中找到原因。
网友评论