国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android Fragment 和 FragmentManager 的代碼分析

2019-12-12 03:59:12
字體:
來源:轉載
供稿:網友

這兩天在研究插件化編程,在使用 Fragment 碰到了一些問題,于是查看源碼,順便分析了一下 Fragment 和 FragmentManager 以及其他幾個 API 的原代碼,看看他們是怎么工作的。

我們知道 Fragment 有個 onCreateView() 方法,這個方法在 Fragment 創建 View 的時候被調用,并且返回一個 View 對象。那么 onCreateView 在什么時候被調用呢,咱們在 Fragment 這個類里找到了一個方法,performCreateView() 方法。

Fragment.javapublic 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.javavoid 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 FragmentManagerfinal FragmentManagerImpl mFragments = new FragmentManagerImpl();public FragmentManager getSupportFragmentManager() { return mFragments;}

獲取到 FragmentManager 后,咱們一般就會調用 beginTransaction() 方法,返回一個 FragmentTransaction 。咱們看代碼去。

FragmentManager.javapublic abstract FragmentTransaction beginTransaction();FragmentManagerImpl extends FragmentManager@Overridepublic 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.javafinal 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 的代碼分析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 北票市| 礼泉县| 玉溪市| 云安县| 独山县| 台湾省| 枞阳县| 灵台县| 双峰县| 屏东市| 鹿泉市| 洛浦县| 同心县| 思茅市| 湘阴县| 云和县| 吕梁市| 云安县| 吐鲁番市| 平顺县| 青海省| 五莲县| 泽普县| 任丘市| 邵武市| 琼海市| 延长县| 台湾省| 五家渠市| 临夏县| 叶城县| 团风县| 江门市| 平邑县| 赤城县| 景德镇市| 罗源县| 合川市| 巴马| 克什克腾旗| 金山区|