編輯:關於Android編程
這兩天在研究插件化編程,在使用 Fragment 碰到了一些問題,於是查看源碼,順便分析了一下 Fragment 和 FragmentManager 以及其他幾個 API 的原代碼,看看他們是怎麼工作的。
我們知道 Fragment 有個 onCreateView() 方法,這個方法在 Fragment 創建 View 的時候被調用,並且返回一個 View 對象。那麼 onCreateView 在什麼時候被調用呢,咱們在 Fragment 這個類裡找到了一個方法,performCreateView() 方法。
Fragment.java public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return null; }
performCreateView 這個方法在什麼時候會被調用呢,在 Fragment 裡找不到調用它的代碼。咱們可以猜測一下,大概會在 FragmentManager 裡。
View performCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (mChildFragmentManager != null) { mChildFragmentManager.noteStateNotSaved(); } return onCreateView(inflater, container, savedInstanceState); }
在 FragmentManager 裡,咱們找到了調用 Fragment.performCreateView 的代碼,在 moveToState() 方法裡,這個方法有點大,我只粘貼了部分代碼。可以看到,它會在 Fragment 初始化或者創建的時候被調用。並且我們知道,創建的View 被賦值給 Fragment 的 mView 成員變量了。
FragmentManager.java void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { switch (f.mState) { case Fragment.INITIALIZING: if (f.mFromLayout) { f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), null, f.mSavedFragmentState); } break; case Fragment.CREATED: if (!f.mFromLayout) { f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), container, f.mSavedFragmentState); } break; } }
接下來,咱們要看什麼時候會調用 moveToState() 這個方法。找了一下,發現很 N 多的地方調用了這個方法。這樣給咱們逆推找代碼造成了一定的難度。於是咱們換個思路,正推來分析。怎麼正推了,看咱們怎麼使用 Fragment 和 FragmentManager 來分析。
一般咱們都是 getFragmentManager() 或者 getSupportFragmentManager() 的方法來獲取 FragmentManager.以 FragmentActivity 為例,一般情況下,咱們在這個類的子類裡調用這兩個方法之一。
咱們在 FragmentActivity 裡找到了相應的代碼。FragmentManager 是一個抽象類,FragmentManagerImpl 是 FragmentManager 的子類,在 FragmentManager 同一個 java 文件內,是一個內部類。它是 FragmentManager 的實現。
FragmentActivity.java //FragmentManagerImpl is subclass of FragmentManager final FragmentManagerImpl mFragments = new FragmentManagerImpl(); public FragmentManager getSupportFragmentManager() { return mFragments; }
獲取到 FragmentManager 後,咱們一般就會調用 beginTransaction() 方法,返回一個 FragmentTransaction 。咱們看代碼去。
FragmentManager.java public abstract FragmentTransaction beginTransaction(); FragmentManagerImpl extends FragmentManager @Override public FragmentTransaction beginTransaction() { return new BackStackRecord(this); } /** * Static library support version of the framework's {@link android.app.FragmentTransaction}. * Used to write apps that run on platforms prior to Android 3.0. When running * on Android 3.0 or above, this implementation is still used; it does not try * to switch to the framework's implementation. See the framework SDK * documentation for a class overview. */ public abstract class FragmentTransaction
我們發現 FragmentManager 是一個抽象方法,實現在 FragmentManagerImpl。FragmentManagerImpl.beginTransaction() 返回的是一個BackStackRecord,而 FragmentTransaction 是一個抽象類。那麼 BackStackRecord 是個什麼鬼。
我們找到了 BackStackRecord 這個類。我們注意到,它繼承於 FragmentTransaction,並且實現了 Runable 接口。它的方法有很多,咱們就分析一個咱們比較常用的,比如 add() 方法。
BackStackRecord.java final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, Runnable final FragmentManagerImpl mManager; public BackStackRecord(FragmentManagerImpl manager) { mManager = manager; }
add() 方法其實沒干啥,咱們一路追下去看。
public FragmentTransaction add(Fragment fragment, String tag) { doAddOp(0, fragment, tag, 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); } 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() 就斷了,好像啥事也沒干。不過它大概是在一個 add 操作添加到一個鏈表上了。那咱們怎麼辦呢?一般咱們add 完後會 commit 一下,咱們看看 commit 都干了啥。
public int commit() { return commitInternal(false); } int commitInternal(boolean allowStateLoss) { if (mCommitted) throw new IllegalStateException("commit already called"); mCommitted = true; if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } mManager.enqueueAction(this, allowStateLoss); return mIndex; }
commit 好像也沒干啥特殊的事情,不過可以看到這麼一行代碼 mManager.enqueueAction(this, allowStateLoss); 看 enqueueAction 這個方法名,應該會做點事情的。
同樣,咱們在 FragmentManagerImpl 裡找到了這個方法。
public void enqueueAction(Runnable action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mDestroyed || mActivity == null) { throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<Runnable>(); } mPendingActions.add(action); if (mPendingActions.size() == 1) { mActivity.mHandler.removeCallbacks(mExecCommit); mActivity.mHandler.post(mExecCommit); } } }
這個方法把咱們的 BackStackRecord -- 其實是 FragmentTransaction,也是 Runnable -- 添加到一個 mPendingActions 的 ArrayList 裡了。然後調用 mActivity.mHandler.post(mExecCommit); mExecCommit 又是什麼鬼?
Runnable mExecCommit = new Runnable() { @Override public void run() { execPendingActions(); } }; mActivity.mHandler.post(mExecCommit); 說明它在主線程裡執行了 mExecCommit 的 run 方法。別問我咋知道的。 execPendingActions() 方法稍微比較大,我把注釋寫在代碼裡。 public boolean execPendingActions() { if (mExecutingActions) { throw new IllegalStateException("Recursive entry to executePendingTransactions"); } //如果不是在主線程,拋出一個異常。 if (Looper.myLooper() != mActivity.mHandler.getLooper()) { throw new IllegalStateException("Must be called from main thread of process"); } boolean didSomething = false; // 這裡有一個 while true 循環。 while (true) { int numActions; // 這裡在一個同步語句塊裡,把上次 mPendingActions 裡的元素轉移到 mTmpActions 數組裡。並且執行 run方法。執行誰的 run 方法呢?!就是 BackStackRecord , 也就是 FragmentTransaction 。我在最後面貼了 BackStackRecord 的 run 方法。 synchronized (this) { if (mPendingActions == null || mPendingActions.size() == 0) { break; } numActions = mPendingActions.size(); if (mTmpActions == null || mTmpActions.length < numActions) { mTmpActions = new Runnable[numActions]; } mPendingActions.toArray(mTmpActions); mPendingActions.clear(); mActivity.mHandler.removeCallbacks(mExecCommit); } mExecutingActions = true; for (int i=0; i<numActions; i++) { mTmpActions[i].run(); mTmpActions[i] = null; } mExecutingActions = false; didSomething = true; } // 這裡有好幾行代碼,不知道干啥的,反正就是做了一些判斷,最後可能會調用 startPendingDeferredFragments() 方法。 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(); } } return didSomething; }
startPendingDeferredFragments 方法又是一坨不知道啥意思的代碼。最後可能調用了 performPendingDeferredStart()
void startPendingDeferredFragments() { if (mActive == null) return; for (int i=0; i<mActive.size(); i++) { Fragment f = mActive.get(i); if (f != null) { performPendingDeferredStart(f); } } }
在 這個方法裡,咱們看到了很熟悉的 moveToState() 方法。接著就是上面的分析,Fragment 的 onCreateView 會被調用。
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); } }
咱們在回來看 BackStackRecord 的 run 方法。這坨代碼有點大,我還是寫注釋在代碼裡。
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); TransitionState state = null; SparseArray<Fragment> firstOutFragments = null; SparseArray<Fragment> lastInFragments = null; if (SUPPORTS_TRANSITIONS) { firstOutFragments = new SparseArray<Fragment>(); lastInFragments = new SparseArray<Fragment>(); calculateFragments(firstOutFragments, lastInFragments); state = beginTransition(firstOutFragments, lastInFragments, false); } int transitionStyle = state != null ? 0 : mTransitionStyle; int transition = state != null ? 0 : mTransition; // 注意這裡要開始 while 循環了,要遍歷剛才咱們說的鏈表了。 Op op = mHead; while (op != null) { int enterAnim = state != null ? 0 : op.enterAnim; int exitAnim = state != null ? 0 : op.exitAnim; switch (op.cmd) { // OP_ADD 很簡單,mManager.addFragment(f, false); 其他的幾個也類似,調用 mManager 相應的方法。 case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.addFragment(f, false); } break; case OP_REPLACE: { Fragment f = op.fragment; if (mManager.mAdded != null) { for (int i=0; i<mManager.mAdded.size(); i++) { Fragment old = mManager.mAdded.get(i); if (FragmentManagerImpl.DEBUG) Log.v(TAG, "OP_REPLACE: adding=" + f + " old=" + old); if (f == null || old.mContainerId == f.mContainerId) { if (old == f) { op.fragment = f = null; } else { if (op.removed == null) { op.removed = new ArrayList<Fragment>(); } op.removed.add(old); old.mNextAnim = exitAnim; if (mAddToBackStack) { old.mBackStackNesting += 1; if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " + old + " to " + old.mBackStackNesting); } mManager.removeFragment(old, transition, transitionStyle); } } } } if (f != null) { f.mNextAnim = enterAnim; mManager.addFragment(f, false); } } break; case OP_REMOVE: { Fragment f = op.fragment; f.mNextAnim = exitAnim; mManager.removeFragment(f, transition, transitionStyle); } break; case OP_HIDE: { Fragment f = op.fragment; f.mNextAnim = exitAnim; mManager.hideFragment(f, transition, transitionStyle); } break; case OP_SHOW: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.showFragment(f, transition, transitionStyle); } break; case OP_DETACH: { Fragment f = op.fragment; f.mNextAnim = exitAnim; mManager.detachFragment(f, transition, transitionStyle); } break; case OP_ATTACH: { Fragment f = op.fragment; f.mNextAnim = enterAnim; mManager.attachFragment(f, transition, transitionStyle); } break; default: { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); } } op = op.next; } // 最後還調用了moveToState() 這個方法。跟剛才的區別,看最後一個參數,一個true,一個false。 // 而且注意,這行代碼在 while 循環之後。 mManager.moveToState(mManager.mCurState, transition, transitionStyle, true); if (mAddToBackStack) { mManager.addBackStackState(this); } }
以上所述是小編給大家介紹的Android Fragment 和 FragmentManager 的代碼分析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!
Android項目:手機安全衛士(16)—— 復雜 ListView1 介紹接著昨天的內容,今天繼續完善應用列表,首先,應用分為系統應用和用戶應用
使用volley進行網絡請求:需先將volley包導入androidstudio中File下的Project Structrue,點加號導包 volley網絡請
Java和Android這對搭檔目前也在風雨飄搖中。技術圈子的事,往往被商業利益牽著鼻子走。世事莫過於此。Java8目前Android應用開發已經使用到Java7,但對J
簡介: 在自定義view的時候,其實很簡單,只需要知道3步驟: 1.測量——onMeasure():決定View的大小 2.布局—&m