Fragment 知識梳理(1) - Fragment 源碼解析

一刽宪、概述

官方是從3.0開始引入Fragment的厘贼,在文檔中有對于其使用的詳細(xì)介紹,可以看出來纠屋,在它剛出現(xiàn)時大家對于它是十分推崇的涂臣。然而隨著使用Fragment開發(fā)的項(xiàng)目越來越多,在一些復(fù)雜場景下逐漸暴露出了它的一些問題售担,對于是否繼續(xù)使用Fragment大家也有不同的看法赁遗。目前在項(xiàng)目中也有大量之前留下來的使用 Fragment的代碼, monkey有時會跑出一些莫名奇妙的問題族铆,在這里我們對于使用Fragment的好壞先不做評價岩四,而是看看它內(nèi)部整個的實(shí)現(xiàn)過程,學(xué)習(xí)它的思想哥攘,在以后出現(xiàn)問題的時候也方便排查剖煌,同時大家可以根據(jù)自己的需求來決定是否使用Fragment材鹦。

二、Fragment事務(wù)的執(zhí)行過程

在操作Fragment時耕姊,第一件是就是通過ActivitygetFragmentManger()方法得到一個FragmentManager對象:

Fragment manager = getFragmentManager();

我們看一下Activity.java中的這個方法:

final FragmentController mFragments = FragmentController.createController(new HostCallbacks())

public FragmentManager getFragmentManager() {
    return mFragments.getFragmentManager();
}

class HostCallbacks extends FragmentHostCallback<Activity> {
    public HostCallbacks() {
        super(Activity.this);
    }
}

可以看到getFragmentManager()調(diào)用的是FragmentController的接口桶唐,那么我們再看看這個類對應(yīng)的方法:

private final FragmentHostCallback<?> mHost;

public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
   return new FragmentController(callbacks)
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}

public FragmentManager getFragmentManager() {
   return mHost.getFragmentManagerImpl();
}

原來FragmentController是把一個callback給包裝了起來,真正完成任務(wù)的是FragmentHostCallback

final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

FragmentManagerImpl getFragmentManagerImpl() {
    return mFragmentManagerImpl;
}

那么結(jié)論就是我們實(shí)際得到的是Activity#mFragments#mHost#mFragmentManagerImpl這個變量茉兰,得到這個實(shí)例之后尤泽,我們通過它的beginTransition方法得到一個事務(wù):

FragmentTransation transation = manager.beginTransation();

我們看一下這個FragmentTransation究竟是個什么東西,FragmentManagerImplFragmentManager的一個內(nèi)部類规脸,它實(shí)現(xiàn)了該接口:

final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {

public FragmentTransaction beginTransation() {
    return new BackStackRecord(this);
}

}

原來這個FragmentTransation也是一個接口坯约,它的實(shí)現(xiàn)是BackStackRecord,并且在每次 beginTransaction時都是返回一個新的事務(wù)對象莫鸭,包括之后進(jìn)行的后退操作都是通過這個事務(wù)對象來管理的闹丐,這個對象中保存了創(chuàng)建它的FragmentManagerImpl實(shí)例。
BackStackRecord其實(shí)是BackStackState的一個內(nèi)部類被因,我們平時就是通過它來進(jìn)行add卿拴、remove、replace梨与、attach巍棱、detach、hide蛋欣、show等操作的航徙,進(jìn)入源碼看一下這些操作背后都干了些什么:

final class BackStackRecord extends FragmentTransation implements FragmentManager.BackStackEntry, Runnable {

public FragmentTransation add(Fragment fragment, String tag) {
    doAddOp(0, fragment, tag, OP_ADD);
    return this;
}

public FragmentTransation add(int containerViewId, Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

public FragmentTransation add(int containerViewId, Fragment fragment, String tag) {
    doAddOp(containerViewId, fragment, tag, OP_ADD);
}

public FragmentTransation replace(int containerViewId, Fragment fragment) {
    return replace(containerViewId, fragment, null);
}

public FragmentTransation replace(int containerViewId, Fragment fragment, String tag) {
    if (containerViewId == 0) {
        //replace操作必須要指定containerViewId.
   }
   doAddOp(containerViewId, fragment, tag, OP_REPLACE);
}

public FragmentTransaction remove(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_REMOVE;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction hide(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_HIDE;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction show(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_SHOW;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction attach(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_ATTACH;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction detach(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_DETACH;
   op.fragment = fragment;
   addOp(op);
}

//新建一個操作,并給操作賦值陷虎。
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)) {
             //如果這個 fragment 之前已經(jīng)有了tag到踏,那么是不允許改變它的。
      }
      fragment.mTag = tag;
   }
   if (containerViewId != 0) {
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            //如果這個fragment已經(jīng)有了mFragmentId尚猿,那么不允許改變它窝稿。
       }
       fragment.mContainerId = fragment.mFragmentId = containerViewId;
   }
   Op op = new Op();
   op.cmd = opcmd;
   op.fragment = fragment;
   addOp(op);
}
//把操作添加到鏈表之中。
void addOp() {
    if (mHead == null) {
        mHead = mTail = op;
    } else {
       op.prev = mTail;
       mTail.next = op;
       mTail = op;
    }
    mNumOp++凿掂;
}
}

看完上面這段代碼伴榔,我們可以得到下面這些信息:

  • 我們調(diào)用這些操作之后僅僅是把這個操作添加到了BackStackRecord當(dāng)中的一個鏈表。
  • 在進(jìn)行attach庄萎、detach踪少、hide、show、remove這五個操作時是不需要傳入containerViewId的,因?yàn)樵趫?zhí)行這些操作之前這個Fragment必然已經(jīng)經(jīng)過了add操作挚躯,它的containerId是確定的。
  • 在執(zhí)行add操作時集漾,需要保證FragmentmTagmContainerViewId在不為空時(也就是這個 Fragment實(shí)例之前已經(jīng)執(zhí)行過add操作)切黔,它們和新傳入的tagcontainerViewId必須是相同的,這是因?yàn)樵?code>FragmentManager的mActive列表中保存了所有被添加進(jìn)去的Fragment具篇,而其提供的 findFragmentById/Tag正是通過這兩個字段作為判斷的標(biāo)準(zhǔn)纬霞,因此不允許同一個實(shí)例在列表當(dāng)中重復(fù)出現(xiàn)兩次。
  • replace操作和add類似驱显,它增加了一個額外條件险领,就是containerViewId不為空,因?yàn)?code>replace需要知道它是對哪個container進(jìn)行操作秒紧,后面我們會看到replace其實(shí)是一個先removeadd的過程,因此`add 的那些判斷條件同樣適用挨下。

那么這個鏈表中的操作什么時候被執(zhí)行呢熔恢,看一下commit()操作:

public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) {
        //已經(jīng)有事務(wù)處理,拋出異常臭笆。
    }
    mCommited = true;
    if (mAddToBackState) {
         mIndex = mManager.allocBackStackIndex(this);
    } else {
         mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
}

它最后調(diào)用了FragmentManagerenqueueAction方法叙淌,我們進(jìn)去看一下里面做了什么:

public void enqueueAction(Runnable action, boolean allowStateLoss) {    
    if (!allowStateLoss) {        
        checkStateLoss();    
    }    
    synchronized (this) {        
        if (mDestroyed || mHost == null) {            
           //如果Activity已經(jīng)被銷毀,那么拋出異常愁铺。          
        }       
        if (mPendingActions == null) {            
            mPendingActions = new ArrayList<Runnable>();        
        }
        //因?yàn)锽ackStackRecord實(shí)現(xiàn)了Runnable接口鹰霍,把加入到其中。        
        mPendingActions.add(action);        
        if (mPendingActions.size() == 1) {        
           mHost.getHandler().removeCallbacks(mExecCommit);            
           mHost.getHandler().post(mExecCommit);        
        }   
    }
}

Runnable mExecCommit = new Runnable {
    public void run() {
        execPendingActions();
    }
}

public boolean execPendingActions() {
   if (mExecutingActions) {
      //已經(jīng)有操作在執(zhí)行茵乱,拋出異常
   }
   if (Looper.myLooper() != mHost.getHandler().getLooper()) {
       //不在主線程中執(zhí)行茂洒,拋出異常
   }
   boolean didSomething = false;
   while (true) {
      int numActions;
      sychronized(this) {
          if (mPendingActions == null || mPendingActions.size == 0) {
               break;
          }
          //期望需要執(zhí)行的事務(wù)個數(shù)
          numActions = mPendingActions.size();
          if (mTmpActions == null || mTmpActions.length < numActions) {
              mTmpActions = new Runnable[numActions];
          }
          mPendingActions.toArray(mTmpActions);
          mPendingActions.clear();
          mHost.getHandler().removeCallbacks(mExecCommit);
       }
       mExecutingActions = true;
       for (int i = 0; i < numActions; i++) {
            //好吧,這里就又回調(diào)了BackStackRecord的run()方法
            mTmpActions[i].run();
            mTmpActions[i] = null;
       }
       mExecutingActions = false;
       didSomething = true; 
   }
}
  • 在調(diào)用commit之后瓶竭,把BackStackRecord加入到FragmentManagerImplmPendingActions中督勺,而且通過查看FragmentManager的源碼也可以發(fā)現(xiàn),所有對mPendingActions的添加操作只有這一個地方調(diào)用斤贰,
  • 當(dāng)其大小為1時智哀,會通過主線程的Handler post一個Runnable mExecCommit出去,當(dāng)這個Runnable執(zhí)行時調(diào)用execPendingActions()方法荧恍。
  • execPendingActions它會拿出這個mPendingActions當(dāng)中的所有Runnable執(zhí)行(如果它是 BackStackRecord調(diào)用過來的瓷叫,那么就是調(diào)用BackStackRecordrun方法),并把這個列表清空送巡。在每個BackStackRecordrun方法執(zhí)行時摹菠,它是通過遍歷BackStackRecord鏈表當(dāng)中每個節(jié)點(diǎn)的cmd來判斷我們之前通過FragmentTransation加入期望執(zhí)行的那些操作的。
  • 可以看出execPendingActions這個方法很關(guān)鍵骗爆,因?yàn)樗鼪Q定了我們添加的操作什么時候會被執(zhí)行辨嗽,我們看下還有那些地方調(diào)用到了它,為什么要分析這個呢淮腾,因?yàn)槲覀冊陧?xiàng)目當(dāng)中發(fā)現(xiàn)很多來自于Fragment的異常都是由我們后面談?wù)摰?code>moveToState方法拋出的糟需,而moveToState執(zhí)行的原因是execPendingActions被調(diào)用了屉佳,因此了解它被調(diào)用的時機(jī)是我們追蹤問題的關(guān)鍵,關(guān)于調(diào)用的時機(jī)洲押,我們都總結(jié)在下面的注釋當(dāng)中了:
<!-- Activity.java -->
final void performStart() {
    mFragments.execPendingActions(); //有可能在 Activity 的 onStart 方法執(zhí)行前
    mInstrumentation.callActivityOnStart(this);
}

final void performResume() {
    performRestart();
    mFragments.execPendingActions(); //如果是從 Stopped 過來的武花,那么有可能在 onStart 到 onResume 之間。
    ....
    mInstrumentation.callActivityOnResume(this);
    ....
    mFragments.dispatchResume(); 
    mFragments.execPendingActions(); //有可能在 onResume 到 onPause 之間杈帐。
}

<!-- FragmentManager.java -->
public void dispatchDestroy() { //這個調(diào)用在 onDestroy 之前体箕。
    execPendingActions();
}

public boolean popBackStackImmediate() {
    executePendingTransactions();
}

public boolean popBackStackImmediate(String name, int flags) {
    executePendingTransactions();
}

關(guān)于FragmentManager的討論我們先暫時放一放,看一下BackStackRecord是怎么執(zhí)行鏈表內(nèi)部的操作的:

public void run() {
    Op op = mHead;
    while (op != null) {
        switch(op.cmd) {
             case OP_ADD:
                 Fragment f = op.fragment;
                 f.mNextAnim = op.enterAnim;
                 mManager.addFragment(f, false);
                 break;
            case OP_REPLACE: {
                Fragment f = op.fragment;
                int containerId = f.mContainerId;
                if (mManager.mAdded != null) {
                    //遍歷 mAdded列表挑童,找到 containerId 相同的 old Fragment.
                    if (old == f) {
                        op.fragment = f = null;
                    } else {
                        if (op.removed == null) {
                             op.removed = new ArrayList<Fragment>();
                        }
                        op.removed.add(old); //這里要把replace之前的記下來是為了后退棧準(zhǔn)備的累铅。
                        if (mAddToBackStack) {
                             old.mBackStackNesting += 1;
                        }
                        mManager.removeFragment(old, transition, transitionStyle);
                    }
                }
                if (f != null) { 
                     f.addFragment(f, false);
                }
                break;
                //后面的remove,hide,show,attach,detach就是調(diào)用了FragmentManager中相應(yīng)的方法,沒什么特別的站叼,就不貼出來了
                case xxx:
                   
            }
        }
        op = op.next;
    }
    //mCurState此時為FragmentManager當(dāng)前的狀態(tài)娃兽,其余的參數(shù)不用管。    
    mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); 
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    } 
}

我們來看一下FragmentManagerImpl對應(yīng)的addFragment等操作:

public void addFragment(Fragment fragment, boolean moveToStateNow) {
   makeActive(fragment); //加入到mActive列表中尽楔。
   if (!fragment.mDetached) {
       if (mAdd.contains(fragment)) {
           //已經(jīng)在mAdded列表投储,拋出異常。
       }
       mAdded.add(fragment);
       fragment.mAdded = true;
       fragment.mRemoving = false;
       if (moveToStateNow) {
           moveToState(fragment);
       }
   }
}

public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
    final boolean inactive = !fragment.isInBackStack();
    if (!fragment.mDetach || inactive) {
        if (mAdded != null) {
            mAdded.remove(fragment); //從mAdded列表中移除阔馋。
        }
        fragment.mAdded = false;
        fragment.mRemoving = true;
        //這里會根據(jù)是否加入后退棧來判斷新的狀態(tài)玛荞,最后會影響到Fragment生命周期的調(diào)用,如果是沒有加入后退棧的呕寝,那么會多調(diào)用onDestroy勋眯、onDetach方法。
        moveToState(fragment, inactive ? Fragment.INITIALZING : Fragment.CREATED, transition, transitionStyle, false); 
    }
}

public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
    if (!fragment.mHidden) {
       fragment.mHidden = true;
       if (fragment.mView != null) {
          fragment.mView.setVisibility(View.GONE);
       }
    }
    fragment.onHiddenChanged(true);
}

public void showFragment(Fragment fragment, int transition, int transitionStyle) {
    if (fragment.mHidden) {
        fragment.mHidden = false;
        if (fragment.mView != null) {
             fragment.mView.setVisibility(View.VISIBLE);
        }
        fragment.onHiddenChanged(false);
    }
}

public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
    if (!fragment.mDetached) {
        fragment.mDetached = true;
        if (fragment.mAdded) {
             if (mAdded != null) {
                 mAdded.remove(fragment);
             }
             fragment.mAdded = false;
             moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
        }
    }
}

public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
    if (fragment.mDetached) {
         if (!fragment.mAdded) {
              if (mAdded.contains(fragment)) {
                  //mAdded列表中已經(jīng)有下梢,拋出異常凡恍,
              }
              mAdded.add(fragment);
              fragment.mAdded = true;
              moveToState(fragment, mCurState, transition, transitionStyle, false);
         }
    }

}

這里的操作很多,我們需要明白以下幾點(diǎn):

  • mActivemAdded的區(qū)別:mActive表示執(zhí)行過add操作怔球,并且其沒有被移除(移除表示的是在不加入后退棧的情況下被removeFragment)嚼酝,所有被動改變Fragment狀態(tài)的調(diào)用都是遍歷這個列表;而 mAdded則表示執(zhí)行過add操作竟坛,并且沒有執(zhí)行detachFragment/removeFragment闽巩,也就是說Fragment 是存在容器當(dāng)中的,但是有可能是被隱藏的(hideFragment)担汤。
  • attachFragment 必須保證其狀態(tài)是 mDetach 的涎跨,而該屬性的默認(rèn)值是 false,只有在執(zhí)行過 detach 方法后崭歧,才能執(zhí)行隅很,執(zhí)行它會把 f.mView 重新加入到 container 中。
  • detachFragment 會把 f.mViewcontainer 中移除率碾。
  • removeFragmentdetachFragment 會強(qiáng)制改變 Fragment 的狀態(tài)叔营,這是因?yàn)樗鼈冃枰淖?Fragment 在布局中的位置屋彪,而這通過被動地接收 FragmentManager 狀態(tài)(即所在Activity的狀態(tài))是無法實(shí)現(xiàn)的。在 removeFragment 時绒尊,會根據(jù)是否加入后退棧來區(qū)分畜挥,如果假如了后退棧,因?yàn)橛锌赡苤髸赝擞て祝赝藭r遍歷的是 mActive 列表蟹但,如果把它的狀態(tài)置為Fragment.INITIALZING,那么在 moveToState方法中就會走到最后一步谭羔,把它從mActive列表中移除华糖,就找不到了也就無法恢復(fù),因此這種情況下Fragment最終的狀態(tài)的和detachFragment是相同的瘟裸。
  • 在加入后退棧時客叉,detachFragment 時,會把 mDetach置為true景描,這種情況下之后可以執(zhí)行 attachFragment操作但不能執(zhí)行 addFragment操作;removeFragment 之后可以執(zhí)行 addFragment操作但不能執(zhí)行 attachFragment操作秀撇。
  • showFragmenthideFragment 并不會主動改變 Fragment 的狀態(tài)超棺,它僅僅是回調(diào) onHiddenChanged方法,其狀態(tài)還是跟著 FragmentManager 來走呵燕。
mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); 

這個方法才是 Fragment的核心棠绘,它的思想就是根據(jù) Fragment 期望進(jìn)入的狀態(tài)和之前的狀態(tài)進(jìn)行對比,從而調(diào)用 Fragment相應(yīng)的生命周期再扭,那么問題就來氧苍,什么是期望進(jìn)入的狀態(tài)呢,我認(rèn)為可以這么理解:

  • 用戶沒有進(jìn)行主動操作泛范,但是 FragmentFragmentManager的狀態(tài)不一致让虐,這時需要發(fā)生變化。
  • 用戶進(jìn)行了主動操作罢荡,無論FragmentFragmentManager的狀態(tài)是否一致赡突,因?yàn)?Fragment 的狀態(tài)發(fā)生了變化,因此這時也需要執(zhí)行区赵。

這里我們?yōu)榱撕啽闫鹨娤瓤匆幌潞蜕芷谟嘘P(guān)的代碼:


static final int INITIALIZING = 0;     // Not yet created.
static final int CREATED = 1;          // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3;          // Fully created, not started.
static final int STARTED = 4;          // Created and started, not resumed.
static final int RESUMED = 5;          // Created started and resumed.

void moveToState(int newState, int transit, int transitStyle, boolean always) {
   if (!always && mCurState == newState) {
      return;
   }
   mCurState = newState;
   if (mActive != null) {
       for (int i = 0; i < mActive.size; i++) {
           //在addFragment中通過makeActive加入進(jìn)去
           Fragment f = mActive.get(i);
           moveToState(f, newState, transit, transitStyle, false);
       }
   }
}

void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
    if (f.mState < newState) { //新的狀態(tài)高于當(dāng)前狀態(tài)
        switch(f.mState) {
             case Fragment.INITIALZING:
                 f.onAttach(mHost.getContext());
                 if (f.mParentFragment == null) {
                     mHost.onAttachFragment(f);
                 }
                 if (!f.mRetaining) {
                     f.performCreate(f.mSavedFragmentState);
                 }
                 if (f.mFromLayout) {
                     f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
                     if (f.mHidden) f.mView.setVisibility(View.GONE);
                     f.onViewCreated(f.mView, f.mSavedFragmentState);
                 }
             case Fragment.CREATED:
                  if (newState > Fragment.CREATED) {
                      if (!f.mFromLayout) {
                          ViewGroup container = null;
                          if (f.mCotainerId != null) {
                               cotainer = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                               if (container == null && !f.mRestored) {
                                  //no view found
                               }
                          }
                          f.mContainer = container;
                          f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState); 
                          if (f.mView != null) {
                               f.mInnerView = f.mView;
                               if (Build.VERSION.SDK >= 11) {
                                   ViewCompact.setSaveFromParentEnable(f.mView, false);
                               } else {
                                   f.mView = NoSaveStateFrameLayout.wap(f.mView);
                               }
                               if (f.mHidden) f.mView.setVisibility(View.GONE);
                               f.onViewCreated(f.mView, f.mSavedFragmentState);
                          } else {
                               f.mInnerView = null;
                          }
                      }
                      f.performActivityCreated(f.mSavedFragmentState);
                  }
             case Fragment.ACTIVITY_CRREATED:
             case Fragment.STOPPED:
                 if (newState > Fragment.STOPPED) {
                      f.performStart();
                 }
             case Fragment.STARTED:
                 if (newState > Fragment.STARTED) {
                      f.performResume();
                 }
        }
    } else if (f.mState > newState) { //新的狀態(tài)低于當(dāng)前狀態(tài)
        switch(f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    f.performPause();
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    f.performStop();
                }
            case Fragment.STOPPED::
                if (newState < Fragment.STOPPED) {
                    f.performReallyStop();
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    f.performDestroyView(); //調(diào)用onDestory()
                    if (f.mView != null && f.mContainer != null) {
                        f.mContainer.removeView(f.mView); //把Fragment的View從視圖中移除惭缰。
                   }
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                      if (f.mAnimationAway != null) {
                          ...
                      } else {
                           if (!f.mRetaining) {
                               f.performDestory();
                           } else {
                              f.mState = Fragment.INITIALIZING;
                           }
                           f.onDetach();
                           if (!f.mRetaining) {
                               makeInActive(f);//把Fragment從mActive中移除,并把Fragment的所有狀態(tài)恢復(fù)成初始狀態(tài)笼才,相當(dāng)于它是一個全新的Fragment漱受。
                           } else {
                               f.mHost = null;
                               f.mParentFragment = null;
                               f.mFragmentManager = null;
                               f.mChildFragmentManager = null;
                           }
                      }
                }
        }
}

moveToState方法中,我們看到了許多熟悉的面孔骡送,就是我們平時最常談到的 Fragment 的生命周期昂羡,通過這段代碼我們就可以對它的生命周期有更加直觀的理解絮记。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市紧憾,隨后出現(xiàn)的幾起案子到千,更是在濱河造成了極大的恐慌,老刑警劉巖赴穗,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件憔四,死亡現(xiàn)場離奇詭異,居然都是意外死亡般眉,警方通過查閱死者的電腦和手機(jī)了赵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甸赃,“玉大人柿汛,你說我怎么就攤上這事〔憾裕” “怎么了络断?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長项玛。 經(jīng)常有香客問我貌笨,道長,這世上最難降的妖魔是什么襟沮? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任锥惋,我火速辦了婚禮,結(jié)果婚禮上开伏,老公的妹妹穿的比我還像新娘膀跌。我一直安慰自己,他們只是感情好固灵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布捅伤。 她就那樣靜靜地躺著,像睡著了一般巫玻。 火紅的嫁衣襯著肌膚如雪暑认。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天大审,我揣著相機(jī)與錄音蘸际,去河邊找鬼。 笑死徒扶,一個胖子當(dāng)著我的面吹牛粮彤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼导坟,長吁一口氣:“原來是場噩夢啊……” “哼屿良!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惫周,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤尘惧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后递递,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喷橙,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年登舞,在試婚紗的時候發(fā)現(xiàn)自己被綠了贰逾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡菠秒,死狀恐怖疙剑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情践叠,我是刑警寧澤言缤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站禁灼,受9級特大地震影響管挟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匾二,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一哮独、第九天 我趴在偏房一處隱蔽的房頂上張望拳芙。 院中可真熱鬧察藐,春花似錦、人聲如沸舟扎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睹限。三九已至譬猫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間羡疗,已是汗流浹背染服。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叨恨,地道東北人柳刮。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秉颗。 傳聞我的和親對象是個殘疾皇子痢毒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容