最近遇到了一个Crash,于是想探究一下Fragment在onCreateView之前都干了什么?生命周期是如何跟Activity同步的?Fragment的视图又是如何添加到布局中的?
一步一步来探究。
以API 24为例
从一个简单的调用开始:
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = QrGenerateFragment.newInstance("a", "b");
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commitAllowingStateLoss();
这里涉及到了几个类:FragmentManager,FragmentManagerImpl,FragmentTransaction,BackStackRecord
先看beginTransaction
FragmentManager.java
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
其实是创建了一个BackStackRecord。从字面意思理解,就是回退栈的记录。
同时将FragmentManager的实例传给BackStackRecord
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
然后是replace(R.id.container, fragment)
FragmentTransaction.java
@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
return replace(containerViewId, fragment, null);
}
@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
传入一个ViewGroup的id,fragment实例,之后,tag设置为null
这里OP_REPLACE是代表什么操作:
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;
这里传的是OP_REPLACE,
如果是add的方式,就是OP_ADD
然后来看一下doAddOp
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
final Class fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
// 一开始是进行一些状态的判断
if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|| (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
+ " must be a public static class to be properly recreated from"
+ " instance state.");
}
// 然后给fragment的manager赋值
fragment.mFragmentManager = mManager;
// 判断的tag的一致性,如果tag不一致,就报错
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) {
// View.NO_ID是-1
if (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
// fragmentId跟containerViewId不一致也报错,应该是之前有在其他的container里用过。
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
// 这里可以看出,会把containerViewId赋值给fragmentId
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
Op是一个回退栈存储内容
static final class Op {
Op next;
Op prev;
int cmd;
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
ArrayList<Fragment> removed;
}
用于双向链表结构,Op包括上一个,下一个,还有动画参数等
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++;
}
然后把新的Op加到链表中
这里replace就看完了.
下面是commitAllowingStateLoss
在BackStackRecord中
/**
* Entry of an operation on the fragment back stack.
*/
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable {
BackStackRecord是继承自FragmentTransaction的,并且实现了Runnable接口
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
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) {
// 如果之前添加到回退栈里,会分配一个id,这里暂时不深究
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
// 把BackStackRecoed实例传入
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
FragmentManager
/**
* Adds an action to the queue of pending actions.
*
* @param action the action to add
* @param allowState