前一阵子和朋友聊技术的时候在讨论fragment的实现的时候,突发奇想想看看他们对谷歌是如何实现fragment的,我的看法是可以通过对viewgroup的addview操作来实现fragment的添加以及别的操作,下面进入正题。
先在这里给大家介绍一个网站:https://searchcode.com/,这个网站可以通过类名直接去找源码。
首先我们都知道FragmentManager是谷歌提供给我们的fragment的管理类,可以通过这个类去执行fragment的相关操作。但是仔细观察源码我们就会发现FragmentManager(下文会用fm代替)是一个抽象类,他的实现类是FragmentManagerImpl。之后根据上面给的网站去检索这个类。
final class FragmentManagerImpl extends FragmentManager{
ArrayList mActive;
FragmentActivity mActivity;
//保存fragment
ArrayList mAdded;
//保存FragmentTransaction
ArrayList mAvailBackStackIndices;
ArrayList mAvailIndices;
ArrayList mBackStack;
ArrayList mBackStackChangeListeners;
ArrayList mBackStackIndices;
ArrayList mCreatedMenus;
}
从代码上我们可以看出来,这个类里面实例化了几个LIST去保存fragment,同时,会传入activity属性。根据这个FragmentManager暴露的方法我们也可以简单的猜测到其作用是用来保存fragment实例,以方便下次调用。
之后我们分析下我们执行fragment操作的关键类FragmentTransaction(下文用ft来代替),同样的这个类也是一个抽象类,他的实例是BackStackRecord,他在实例化的时候会传入当前的FragmentManager。
首先我们先看看调用这个BackStackRecord的add方法。
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
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);
}
根据这两段代码,可以看出来当我们可以看出来当我们通过ft的添加指令之后,只是在ft的执行队列中增加了一个执行动作而已。
当完成这些添加动作之后我们会去执行ft的commit操作。那么commit到底执行了些什么。
public int commit() {
return commitInternal(false);
}
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);
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
这段代码粗浅的看,好像看不出到底做了哪些操作,这个时候我们要回到fm类中去看看调用的方法。
public int allocBackStackIndex(BackStackRecord backstackrecord) {
this;
JVM INSTR monitorenter ;
int j;
if(mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
if(mBackStackIndices == null)
mBackStackIndices = new ArrayList();
int i = mBackStackIndices.size();
if(DEBUG)
Log.v("FragmentManager", (new StringBuilder()).append("Setting back stack index ").append(i).append(" to ").append(backstackrecord).toString());
mBackStackIndices.add(backstackrecord);
j = i;
} else {
int k = ((Integer)mAvailBackStackIndices.remove(-1 + mAvailBackStackIndices.size())).intValue();
if(DEBUG)
Log.v("FragmentManager", (new StringBuilder()).append("Adding back stack index ").append(k).append(" with ").append(backstackrecord).toString());
mBackStackIndices.set(k, backstackrecord);
j = k;
}
return j;
}
首先是这个方法,这个是在fm的list里面加入ft这个类,添加缓存。
public void enqueueAction(Runnable runnable, boolean flag) {
if(!flag)
checkStateLoss();
this;
JVM INSTR monitorenter ;
if(mActivity == null)
throw new IllegalStateException("Activity has been destroyed");
break MISSING_BLOCK_LABEL_33;
Exception exception;
exception;
throw exception;
if(mPendingActions == null)
mPendingActions = new ArrayList();
//核心部分代码
mPendingActions.add(runnable);
if(mPendingActions.size() == 1) {
mActivity.mHandler.removeCallbacks(mExecCommit);
mActivity.mHandler.post(mExecCommit);
}
this;
JVM INSTR monitorexit ;
}
这个是最后一个执行的方法,从中我们可以看出回去调用ft的runnable接口。并让handler去执行这个runnbale方法。
那么最关键的地方来了,runnable方法到底执行了什么代码指令呢。
这里我们只介绍其中一种,就是add属性,下面我会把代码截图上传。
public void run() {
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
if (mAddToBackStack) {
if (mIndex < 0) {
throw new IllegalStateException("addToBackStack() called after commit()");
}
}
bumpBackStackNesting(1);
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
//调用了fragmentmanager的addfragment方法
mManager.addFragment(f, false);
} break;
.......
}
}
}
可以看出主要还是调用了fm里面的方法,ft并没有产生什么别的操作。
那么回到fm里面的addfragment,因为那边代码太长了,所以我只会把核心部分的代码贴出来。
首先要讲的是,无论是那种方式添加fragment的,最终对于fm来说都只是调用了其中的moveToState方法。这个方法会去加载一些我们在fragment中很熟悉的方法。
void moveToState(int i, int j, int k, boolean flag) {
if(fragment.mSavedFragmentState != null) {
fragment.mSavedViewState = fragment.mSavedFragmentState.getSparseParcelableArray("android:view_state");
fragment.mTarget = getFragment(fragment.mSavedFragmentState, "android:target_state");
if(fragment.mTarget != null)
fragment.mTargetRequestCode = fragment.mSavedFragmentState.getInt("android:target_req_state", 0);
fragment.mUserVisibleHint = fragment.mSavedFragmentState.getBoolean("android:user_visible_hint", true);
if(!fragment.mUserVisibleHint) {
fragment.mDeferStart = true;
if(i > 3)
i = 3;
}
}
fragment.mActivity = mActivity;
fragment.mFragmentManager = mActivity.mFragments;
fragment.mCalled = false;
fragment.onAttach(mActivity);
mActivity.onAttachFragment(fragment);
if(!fragment.mRetaining) {
fragment.mCalled = false;
fragment.onCreate(fragment.mSavedFragmentState);
fragment.mRetaining = false;
if(fragment.mFromLayout) {
fragment.mView = fragment.onCreateView(fragment.getLayoutInflater(fragment.mSavedFragmentState), null, fragment.mSavedFragmentState);
if(fragment.mView != null) {
fragment.mInnerView = fragment.mView;
fragment.mView = NoSaveStateFrameLayout.wrap(fragment.mView);
if(fragment.mHidden)
fragment.mView.setVisibility(8);
fragment.onViewCreated(fragment.mView, fragment.mSavedFragmentState);
} else {
fragment.mInnerView = null;
}
}
}
这段代码中我们可以发现,fragment中,所有方法的执行顺序应该是onAttach
->onCreate->onCreateView。
从上面这段代码可以看出当我们在fragment中完成了view的生成之后,代码会继续向下执行,首先会先去实例化出对应的viewgroup,之后再将fragment生成的view存放到这个viewgroup中去。
从这里就能简单的知道fragment以及fm ft的运行方式。