先從fragment基本用法出發:
getSupportFragmentManager().beginTransaction()
.add(R.id.basic, new PageFragment()).commit();複製程式碼
其中點進去getSupportFragmentManager()可以看到跳轉到FragmentActivity:
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}複製程式碼
先看下mFragments是啥:
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}複製程式碼
往下看.
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}複製程式碼
public FragmentManager getSupportFragmentManager() {
return mHost.getFragmentManagerImpl();
}複製程式碼
看樣子是呼叫了FragmentHostCallback的getFragmentManagerImpl(),往下看HostCallbaks的程式碼:
class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
@Override
public LayoutInflater onGetLayoutInflater() {
return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this);
}
//程式碼省略...
@Override
public FragmentActivity onGetHost() {
return FragmentActivity.this;
}
@Override
public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);
}
//程式碼省略...
@Override
public void onStartActivityFromFragment(
Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) {
FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode, options);
}
@Override
public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
@NonNull String[] permissions, int requestCode) {
FragmentActivity.this.requestPermissionsFromFragment(fragment, permissions,
requestCode);
}
@Override
public void onAttachFragment(Fragment fragment) {
FragmentActivity.this.onAttachFragment(fragment);
}
//程式碼省略...
@Nullable
@Override
public View onFindViewById(int id) {
return FragmentActivity.this.findViewById(id);
}
//程式碼省略...
}複製程式碼
先有個印象,這裡還有startActivity這樣的方法,其實Fragment中啟動的方法都是呼叫這裡的,而且HostCallbacks是FragmentActivity的內部類,所以構造方法直接持有了Activity引用.
這裡沒找到getSupportFragmentManager()方法,再看看它的父類:
public abstract class FragmentHostCallback<E> extends FragmentContainer {
private final Activity mActivity;
final Context mContext;
private final Handler mHandler;
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
//省略大部分程式碼
public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
this(context instanceof Activity ? (Activity) context : null, context, handler,
windowAnimations);
}
FragmentHostCallback(FragmentActivity activity) {
this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}
FragmentHostCallback(Activity activity, Context context, Handler handler,
int windowAnimations) {
mActivity = activity;
mContext = context;
mHandler = handler;
mWindowAnimations = windowAnimations;
}
/**
* Return a {@link LayoutInflater}.
* See {@link Activity#getLayoutInflater()}.
*/
public LayoutInflater onGetLayoutInflater() {
return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
Activity getActivity() {
return mActivity;
}
Context getContext() {
return mContext;
}
Handler getHandler() {
return mHandler;
}
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}
}複製程式碼
可以看到子類沒有重寫getSupportFragmentManager()方法,所以獲得的物件就是FragmentMangerImpl了.再繼續往下看beginTransaction()方法:
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}複製程式碼
又可以看到beginTransaction()返回的物件是BacStateRecord,繼續往下看
@Override
public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
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.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 (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
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);
}
@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;
}
@Override
public FragmentTransaction remove(Fragment fragment) {
Op op = new Op();
op.cmd = OP_REMOVE;
op.fragment = fragment;
addOp(op);
return this;
}
@Override
public FragmentTransaction hide(Fragment fragment) {
Op op = new Op();
op.cmd = OP_HIDE;
op.fragment = fragment;
addOp(op);
return this;
}
@Override
public FragmentTransaction show(Fragment fragment) {
Op op = new Op();
op.cmd = OP_SHOW;
op.fragment = fragment;
addOp(op);
return this;
}
複製程式碼
void addOp(Op op) {
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
}複製程式碼
所有add方法和replace方法都呼叫到doAppOp方法,然後最終都回撥到addOp方法。
先看下doAppOp方法,首先先檢測fragment是不是匿名類或者不是公共類或者是成員變數且是靜態的,就丟擲異常.
接下來給fragment賦值,首先就是賦值mFragmentManager為FragmentMangerImpl,如果使用者設定tag,則再設定fragment的tag,如果之前設定過就報錯,mContainerId同理,接下來看Op這個類:
static final class Op {
int cmd;
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
}複製程式碼
就幾個成員變數,cmd都是設為1,然後放入fragment,然後放入設定的動畫.show和hide也呼叫該方法,然後看最後一步commit:
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
@Override
public void commitNow() {
disallowAddToBackStack();
mManager.execSingleAction(this, false);
}
@Override
public void commitNowAllowingStateLoss() {
disallowAddToBackStack();
mManager.execSingleAction(this, true);
}
@Override
public FragmentTransaction setAllowOptimization(boolean allowOptimization) {
mAllowOptimization = allowOptimization;
return this;
}
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);
pw.close();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex; 複製程式碼
commit操作都呼叫了commitInternal方法,這裡有個mCommit控制,如果同一個BackStackRecord物件第二次再commit,是會報錯的,DEBUG模式下列印log,
mAddToBackStack賦值在以下程式碼:
@Override
public FragmentTransaction disallowAddToBackStack() {
if (mAddToBackStack) {
throw new IllegalStateException(
"This transaction is already being added to the back stack");
}
mAllowAddToBackStack = false;
return this;
}複製程式碼
如果mAddToBackStack為true,則加入到FragmentManger的一個集合中,並返回在當前集合中的位置,程式碼如下:
public int allocBackStackIndex(BackStackRecord bse) {
synchronized (this) {
if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
if (mBackStackIndices == null) {
mBackStackIndices = new ArrayList<BackStackRecord>();
}
int index = mBackStackIndices.size();
if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
mBackStackIndices.add(bse);
return index;
} else {
int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
mBackStackIndices.set(index, bse);
return index;
}
}
}複製程式碼
public void enqueueAction(OpGenerator 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<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}複製程式碼
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}複製程式碼
判斷mStateSaved是否儲存,如果儲存了則不允許再次
提交,然後報錯,也就是說commit()必須在onSaveInstanceState()方法之前呼叫,不然就是拋異常了.
繼續往下看,這裡用synchronized鎖,如果被銷燬了或者mHost為空,則報異常說activity已經銷燬了,這個mHost是持有activity的引用的.佇列為空則建立佇列,然後加入當前的action,當前action實現的方法如下:
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Run: " + this);
}
records.add(this);
isRecordPop.add(false);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
return true;
}複製程式碼
其實就是加入FragmentManager的佇列而已.繼續看:
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);
}
}
}複製程式碼
mHost.getHandler()其實就是FragmentActivity中的mHandler了,先移除,確保沒有該Callback,然後加入Callback.看下具體實現:
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};複製程式碼
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
return didSomething;
}複製程式碼
再回頭看下commitNow()和commitNowAllowingStateLoss()方法,就是設定禁止加入返回棧,然後execSingleAction方法和execPendingActions()幾乎一模一樣,從這裡看出commit和commitNow()的區別就是一個需要handler佇列來執行,一個直接執行,allowStateLoss還是代表是否檢測.
@Override
public FragmentTransaction disallowAddToBackStack() {
if (mAddToBackStack) {
throw new IllegalStateException(
"This transaction is already being added to the back stack");
}
mAllowAddToBackStack = false;
return this;
}
複製程式碼
public void execSingleAction(OpGenerator action, boolean allowStateLoss) {
ensureExecReady(allowStateLoss);
if (action.generateOps(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
}
doPendingDeferredStart();
}複製程式碼
看下generateOpsForPendingActions(mTmpRecords, mTmpIsPop):
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isPop) {
int numActions;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
return false;
}
numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
mPendingActions.get(i).generateOps(records, isPop);
}
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
return numActions > 0;
}複製程式碼
其實就是執行了上面的generateOps方法,而且mPendingActions執行結束被清空了。
其他程式碼有點繁多,自己有情趣可以去看看,現在重點來看 doPendingDeferredStart():
void doPendingDeferredStart() {
if (mHavePendingDeferredStart) {
boolean loadersRunning = false;
for (int i = 0; i < mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null && f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
if (!loadersRunning) {
mHavePendingDeferredStart = false;
startPendingDeferredFragments();
}
}
}複製程式碼
void startPendingDeferredFragments() {
if (mActive == null) return;
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null) {
performPendingDeferredStart(f);
}
}
}複製程式碼
public void performPendingDeferredStart(Fragment f) {
if (f.mDeferStart) {
if (mExecutingActions) {
// Wait until we're done executing our pending transactions
mHavePendingDeferredStart = true;
return;
}
f.mDeferStart = false;
moveToState(f, mCurState, 0, 0, false);
}
}複製程式碼
由於能力有限,就直接講最重要的 moveToState(f, mCurState, 0, 0, false)方法了.
講這個之前,首先得先講Fragment如何和Activity生命週期聯絡起來.
看下FragmentActivity的onCreate方法:
protected void onCreate(@Nullable Bundle savedInstanceState) {
//程式碼省略..
mFragments.dispatchCreate();
}
public void dispatchCreate() {
mHost.mFragmentManager.dispatchCreate();
}
public void dispatchCreate() {
mStateSaved = false;
mExecutingActions = true;
moveToState(Fragment.CREATED, false);
mExecutingActions = false;
}
void moveToState(int newState, boolean always) {
//程式碼省略..
mCurState = newState;
//程式碼省略..
if (!loadersRunning) {
startPendingDeferredFragments();
}
//程式碼省略..
}
mCurState就是activity當前的生命週期了,然後又呼叫startPendingDeferredFragments()最終還是到moveToState(f, mCurState, 0, 0, false)方法了,其他生命週期同理.
moveToState程式碼量有點多,我就省略大部分程式碼了,所以只講下create流程了.
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
//mContainerId就是add(int containerId,Fragment fragment)傳進來的佈局id,
if (f.mContainerId != 0) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(
"Cannot create fragment "
+ f
+ " for a container view with no id"));
}
//mContainer.onFindViewById等同HostCallbacks.onFindViewById(int id),
//也就是FragmentActivity.this.findViewById(id) container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
String resName;
try {
resName = f.getResources().getResourceName(f.mContainerId);
} catch (NotFoundException e) {
resName = "unknown";
}
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ resName
+ ") for fragment " + f));
}
}
f.mContainer = container;
//執行onCreateView方法,
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
//這裡把返回的view新增進activity的container中,這裡引出一個問題,以前碰到過在
// onCreateView中設定View view = inflater.inflate(R.layout.fragment_page, container, //true);
//會直接蹦,原因就在這裡了,因為設定為true就將子類新增進父類了,然後這裡又進行一次新增操作,就丟擲異常了 if (container != null) {
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
//執行onViewCreated方法
f.onViewCreated(f.mView, f.mSavedFragmentState);
//這裡如果使用者設定過registerFragmentLifecycleCallbacks,就回撥對應的方法.
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
// Only animate the view if it is visible. This is done after
// dispatchOnFragmentViewCreated in case visibility is changed
f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
&& f.mContainer != null;
} else {
f.mInnerView = null;
}
}
//執行onActivityCreated方法,然後同理回撥
f.performActivityCreated(f.mSavedFragmentState);
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}複製程式碼
我覺得以後多Fragment開發可能會越來越火,瞭解一下Fragment的基本流程,還是挺重要的吧。由於能力有限,我只是講下Fragment的流程的一點毛皮,如有錯誤還望指出。
順便推薦下一個大神寫的Fragment框架:github.com/YoKeyword/F…