Fragment深入學習

    本節將對Fragment進行學習和探究,瞭解底層原理。通過一個簡單的使用範例爲入口,層層深入最終分析出FragmentActivity、FragmentTransaction、FragmentManager類之間方法如何調用,對象如何創建,Fragment生命週期如何實現等等問題。通過具體的分析得出結論如下
    在FragmentManager中存在多個moveToState方法,按照參數類型個人將其分兩類,一類是參數中有Fragment的moveToState方法,另一類自然就是參數中無Fragment的moveToState方法。第一類是針對一個特定的Fragment進行操作,主要工作就是將指定的Fragment狀態轉移到FragmentManager的mCurState狀態。第二類就是更新FragmentManager的mCurState狀態!
    Fragment狀態分爲 INITIALIZING、CREATED、ACTIVITY_CREATED、 STOPPED、STARTED、RESUMED共6個狀態。預期狀態(newState)大於Fragment自身的狀態(f.mState < newState)則將Fragment的狀態向前推進對應Fragment的創建過程;預期狀態(newState)小於Fragment自身的狀態(f.mState > newState)則將Fragment的狀態向後推進對應Fragment的銷燬過程。
    不帶Fragment參數的moveToSate方法是將FragmentManager下面的所有Fragment狀態轉移到當前FragmentManager的狀態,該方法內部會調用帶Fragment參數的moveToState方法。FragmentActivity會間接的調用不帶Fragment參數的moveToState方法主要是用於設置當前的FragmentManager的狀態。
    帶Fragment參數的moveToState方法是將參數中的Fragment狀態轉移到當前FragmentManager的狀態。FragmentManager的detachFragment、attachFragment、removeFragment、addFragment等方法不會在FragmentActivity中出現,但是會在FragmentTransaction中的run方法中出現,表明每次提交的事務最終會通過調用這些方法完成實際的Fragment的加載與銷燬。

一個佈局中嵌套多個Fragment範例(平板電腦)

創建Fragment
一、ItemsListFragment佈局文件 
res/layout/fragment_items_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ListView
        android:id="@+id/lvItems"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true" >
    </ListView>
</RelativeLayout>
一、ItemsListFragment對象文件
public class ItemsListFragment extends Fragment {
  private ArrayAdapter<Item> adapterItems; //Item是自定義的一類數據
  private ListView lvItems;
  private OnListItemSelectedListener listener;
  public interface OnListItemSelectedListener {  public void onItemSelected(Item item); } 
  //自定義接口,用於回調實現該接口的Activity相關方法
  @Override public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (activity instanceof OnListItemSelectedListener) {
      listener = (OnListItemSelectedListener) activity;
    } else {
      throw new ClassCastException(
          activity.toString()   + " must implement ItemsListFragment.OnListItemSelectedListener"); 
    }
  }
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ArrayList<Item> items = Item.getItems();
    adapterItems = new ArrayAdapter<Item>(getActivity(), android.R.layout.simple_list_item_activated_1, items); 
  }
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.fragment_items_list, container, false); 
    lvItems = (ListView) view.findViewById(R.id.lvItems);
    lvItems.setAdapter(adapterItems);
    lvItems.setOnItemClickListener(new OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> adapterView, View item, int position, long rowId) { 
        Item item = adapterItems.getItem(position);
        listener.onItemSelected(item); 
      }
    });
    return view;
  }
   public void setActivateOnItemClick(boolean activateOnItemClick) {
        lvItems.setChoiceMode(
        activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
            : ListView.CHOICE_MODE_NONE);
  }
}

二、ItemDetailFragment佈局文件
res/layout/fragment_item_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Item Title"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    <TextView
        android:id="@+id/tvBody"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tvTitle"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="19dp"
        android:text="Item Body" />
</RelativeLayout>

二、ItemDetailFragment對象文件
public class ItemDetailFragment extends Fragment {
    private Item item;
    @Override  public void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState);
       item = (Item) getArguments().getSerializable("item"); //之前通過調用Fragment的setArguments方法傳進來的bundle數據
     }

   @Override  public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) { 
        View view = inflater.inflate(R.layout.fragment_item_detail, container, false); 
        TextView tvTitle = (TextView) view.findViewById(R.id.tvTitle);
        TextView tvBody = (TextView) view.findViewById(R.id.tvBody);
        tvTitle.setText(item.getTitle());
        tvBody.setText(item.getBody());
        return view;
      }
    public static ItemDetailFragment newInstance(Item item) {
        ItemDetailFragment fragmentDemo = new ItemDetailFragment();
        Bundle args = new Bundle();
        args.putSerializable("item", item);
        fragmentDemo.setArguments(args); //getArguments().getSerializable("item")獲取該數據
        return fragmentDemo;
  }
}

創建Activity的佈局文件activity_items_list.xml
一、在layout目錄下添加一個activity_items_list佈局文件
res/layout/activity_items_list.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".ItemsListActivity" >
    <fragment
        android:id="@+id/fragmentItemsList"
        android:name="com.codepath.example.masterdetaildemo.ItemsListFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        tools:layout="@layout/fragment_items_list" />
</RelativeLayout>



二、在layout-large目錄下添加一個同名activity_items_list佈局文件(方法如下)




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:showDividers="middle"
    android:baselineAligned="false"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <fragment
        android:id="@+id/fragmentItemsList"
        android:name="com.codepath.example.masterdetaildemo.ItemsListFragment"
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="1"
        tools:layout="@layout/fragment_items_list" />
    <View android:background="#000000"
        android:layout_width="1dp"
        android:layout_height="wrap_content"
        />
    <FrameLayout
        android:id="@+id/flDetailContainer"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3" />
</LinearLayout>
    <fragment/>標籤用於靜態的在Activity中嵌入Fragment,通過getSupportFragmentManager()  .findFragmentById(R.id.fragmentItemsList)可以獲得該ItemsListFragment對象
    <FrameLayout/>標籤用於動態的在Activity中嵌入Fragment,通過ItemDetailFragment fragmentItem = ItemDetailFragment.newInstance(item);  getSupportFragmentManager(). beginTransaction(). replace(R.id.flDetailContainer, fragmentItem). commit();來動態的顯示創建的fragmentItem對象。
    上面工作完成後我們就有了res/layout-large/activity_items_list.xml和res/layout/activity_items_list.xml兩個同名文件,系統會根據當前設備屏幕情況使用不同的佈局文件。如在平板中使用layout-large/activity_items_list.xml,在普通手機中使用layout/activity_items_list.xml。對於該部分感興趣的同學可以參考博客

創建Activity對象文件
public class ItemsListActivity extends AppCompatActivity implements OnItemSelectedListener {
    private boolean isTwoPane = false; //平板標誌位
  @Override  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_items_list);
    determinePaneLayout(); //判斷當前使用的是哪個Layout文件
  }
 
  private void determinePaneLayout() {
    FrameLayout fragmentItemDetail = (FrameLayout) findViewById(R.id.flDetailContainer); //能夠獲取到FrameLayout表明使用的平板佈局
    if (fragmentItemDetail != null) {  
        isTwoPane = true; 
        ItemsListFragment fragmentItemsList =  (ItemsListFragment) getSupportFragmentManager()
                   .findFragmentById(R.id.fragmentItemsList);
         //因爲ItemsListFragment實在平板佈局文件中寫死的因此可以直接獲取到該Fragment,而不需要使用事務(FragmentTransaction)
        fragmentItemsList.setActivateOnItemClick(true);
    } 
  }
  @Override  public void onItemSelected(Item item) { 
      if (isTwoPane) {
        ItemDetailFragment fragmentItem = ItemDetailFragment.newInstance(item);
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.flDetailContainer, fragmentItem);
        ft.commit();
      } else {
        Intent i = new Intent(this, ItemDetailActivity.class);
        i.putExtra("item", item);
        startActivity(i);
      }
    }
}  

創建適用於普通手機屏幕的ItemDetailActivity和對應的佈局文件
public class ItemDetailActivity extends AppCompatActivity {
  ItemDetailFragment fragmentItemDetail;
  @Override  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_item_detail);
    Item item = (Item) getIntent().getSerializableExtra("item");
    if (savedInstanceState == null) {
      fragmentItemDetail = ItemDetailFragment.newInstance(item); 
      FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
      ft.replace(R.id.flDetailContainer, fragmentItemDetail);
      ft.commit();
    }
  }
}

res/layout/activity_item_detail.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/flDetailContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".ItemDetailActivity" >
</FrameLayout>
上述代碼實現了大體如下的功能:



源碼分析

    下面的分析是以getSupportFragmentManager().beginTransaction().add(R.id.flContainer, new DemoFragment(), "SOMETAG").commit();爲入口一步步分析得出的。注意getSupportFragmentManager()方法只有在FragmentActivity或者其子類中調用纔有效,該方法返回一個FragmentManager對象。下面我們首先從FragmentActivity的getSupportFragmentManager()方法入手

FragmentActivity.class

Fields
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());  
getSupportFragmentManager()@FragmentActivity.class
public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
}
onCreate()@FragmentActivity.class
protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);
        //該方法其最終目的實則是爲了將FragmentController中的HostCallback對象引用傳給FragmentManager,具體分析看FragmentController
        super.onCreate(savedInstanceState);
        NonConfigurationInstances nc =   (NonConfigurationInstances) getLastNonConfigurationInstance(); 
        if (nc != null) {   mFragments.restoreLoaderNonConfig(nc.loaders); } 
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        mFragments.dispatchCreate();
        //該方法最底層會調用FragmentManager的同名方法,對具體的Fragment進行操作
}
 onSaveInstanceState()@FragmentActivity.class
@Override   protected void onSaveInstanceState(Bundle outState) { 
        super.onSaveInstanceState(outState);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p); //存儲當前Fragment保存的FragmentController的狀態
        }
}
FragmentActivity的對於Fragment的所有操作都是通過FragmentController進行的。該類很簡單,具體下面會分析。FragmentActivity會在當前Activity創建時從Bundle中嘗試獲取上次關閉的FragmentManager狀態,會在當前Activity銷燬時將當前FragmentManager的狀態存儲下來。

FragmentController.class

Fields
private final FragmentHostCallback<?> mHost;
createController()@FragmentController.class
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
        return new FragmentController(callbacks);
}
private FragmentController(FragmentHostCallback<?> callbacks) { 
        mHost = callbacks;
}
FragmentController構造器只接受一個FragmentHostCallback對象,其後的所有操作都是通過它來完成的。比如下面幾個常見的方法
public FragmentManager getSupportFragmentManager() {
        return mHost.getFragmentManagerImpl();
}
public void attachHost(Fragment parent) {
        mHost.mFragmentManager.attachController( mHost, mHost /*container*/, parent); 
}
public void dispatchCreate() {
        mHost.mFragmentManager.dispatchCreate();
}
通過上面的幾個方法舉例,很容易得出結論。FragmentController的方法底層要麼是調用FragmentHostCallback的方法,要麼就調用FragmentHostCallback的FragmentManager域的方法完成具體的操作。往下我們就來分析一下FragmentHostCallback對象內部結構。

[email protected] 

class HostCallbacks extends FragmentHostCallback<FragmentActivity>
public HostCallbacks() {
       super(FragmentActivity.this /*fragmentActivity*/);
}
HostCallbacks是一個繼承自FragmentHostCallback的類,定義在FragmentActivity內部。不過大部分我們感興趣的方法都是定義在FragmentHostCallback類中,繼續往下看

FragmentHostCallback.class

Fields
private final Activity mActivity; 
final Context mContext;
private final Handler mHandler;
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
FragmentHostCallback()@FragmentHostCallback.class
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;
}
構造器完成對域中Activity、Handler、FragmentManager的創建初始化。
getFragmentManagerImpl()@FragmentHostCallback.class
FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManager;
}
到此我們對於getSupportFragmentManager()方法的分析到此結束,分析過程中可以很明顯的發現FragmentController中有一個FragmentHostCallback對象,而FragmentHostCallback對象內部擁有當前Activity的context、Handler和一個FragmentManagerImpl對象。FragmentActivity是直接對FragmentController對象進行操作的,而FragmentController底層又是利用FragmentHostCallback對象或者FragmentHostCallback對象的FragmentManager對象完成實際的操作,FragmentManager負責具體的Fragment的創建銷燬生命週期的實現。因此下面我們就來好好分析一下FragmentManager類的底層實現。具體分析流程爲Fragment、FragmentTransaction、FragmentManager。


Fragment.class

public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
Fields
static final Object USE_DEFAULT_TRANSITION = new Object();
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.
int mState = INITIALIZING;
int mContainerId; //當前Fragment所屬的ViewGroup對應的id號
ViewGroup mContainer;
View mView;
View mInnerView;
String mTag; //當前Fragment的標籤
Fragment mParentFragment;
FragmentManagerImpl mChildFragmentManager;
FragmentManagerImpl mFragmentManager;
boolean mFromLayout; //當前Fragment來自於一個Layout
boolean mInLayout; //view has actually been inflated in its layout
boolean mResumed; 
boolean mDetached; //當前Fragment是否和context已經綁定
boolean mAdded; //當前Fragment是否被存儲在FragmentManager的mAdded集合集合中
boolean mRemoving;  //當前Fragment已經存在FragmentManager中則該值爲false
void initState() {
        mIndex = -1;
        mWho = null;
        mAdded = false;
        mRemoving = false;
        mResumed = false;
        mFromLayout = false;
        mInLayout = false;
        mRestored = false;
        mBackStackNesting = 0;
        mFragmentManager = null;
        mChildFragmentManager = null;
        mHost = null;
        mFragmentId = 0;
        mContainerId = 0;
        mTag = null;
        mHidden = false;
        mDetached = false;
        mRetaining = false;
        mLoaderManager = null;
        mLoadersStarted = false;
        mCheckedForLoaderManager = false;
}
該部分只是瞭解Fragment存在哪些域、初始化狀態是什麼,方便後面分析。

BackStackRecord.class (FragmentTransaction)

final class BackStackRecord extends FragmentTransaction implements   FragmentManager.BackStackEntry, Runnable
Fields
final FragmentManagerImpl mManager;
Op mHead;
Op mTail;
int mNumOp;
static final class Op {
        Op next;
        Op prev;
        int cmd;
        Fragment fragment;
        ......
        ArrayList<Fragment> removed;
}
FragmentManager的beginTransaction方法實則是創建瞭如下的一個FragmentTransaction對象
BackStackRecord()@BackStackRecord.class
public BackStackRecord(FragmentManagerImpl manager) {
        mManager = manager;
}
FragmentTransaction中存儲的每個事務實際是一個Op對象,該對象存儲有當前事務的操作類型-cmd、當前事務的操作對象-fragment;下面以add方法爲例進行介紹:
add()@BackStackRecord.class
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;
        } //不能改變Fragment所屬ViewGroup
        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;
        }
        .....
        mNumOp++;
}
將op添加到鏈表尾部
commit()@BackStackRecord.class
該方法是將BackStackRecord.this提交給UI線程去執行,具體執行BackStackRecord.class中實現的run方法
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);} //默認是false
        else {  mIndex = -1; }
        mManager.enqueueAction(this, allowStateLoss); //note1
        return mIndex;
}
1、重點是這裏,將會導致異步執行BackStackRecord的run方法
run()@BackStackRecord.class
public void run() {
        ...
        TransitionState state = null;
        SparseArray<Fragment> firstOutFragments = null;
        SparseArray<Fragment> lastInFragments = null;
        if (SUPPORTS_TRANSITIONS) { //當前版本大於21,Build.VERSION.SDK_INT >= 21則執行下面代碼
            firstOutFragments = new SparseArray<Fragment>();
            lastInFragments = new SparseArray<Fragment>();
            calculateFragments(firstOutFragments, lastInFragments); 
            //Finds the first removed fragment and last added fragments when going forward
            state = beginTransition(firstOutFragments, lastInFragments, false);
        }
        int transitionStyle = state != null ? 0 : mTransitionStyle;
        int transition = state != null ? 0 : mTransition;
        Op op = mHead;   //note1
        while (op != null) {
            ......
            switch (op.cmd) {
                case OP_ADD: { //note2
                    Fragment f = op.fragment;
                    ......
                    mManager.addFragment(f, false);
                } break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    if (mManager.mAdded != null) {
                        for (int i=0; i<mManager.mAdded.size(); i++) {
                            Fragment old = mManager.mAdded.get(i);
                            if (old.mContainerId == containerId) {
                                if (old == f) {  op.fragment = f = null; } 
                                else { 
                                    if (op.removed == null) {  op.removed = new ArrayList<Fragment>();  } 
                                    op.removed.add(old); //存入op的鏈表中
                                    old.mNextAnim = exitAnim;
                                    ......
                                    mManager.removeFragment(old, transition, transitionStyle);
                                } //end of else
                            } //end of  if (old.mContainerId == containerId)
                        } end of for
                    } end of if (mManager.mAdded != null) 
                    if (f != null) {//證明當前的Fragment在FragmentManager的mAdded數組中不存在,需要添加到該數組中
                        ......
                        mManager.addFragment(f, false);
                    }
                } break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    ......
                    mManager.removeFragment(f, transition, transitionStyle); //後面的兩個參數在分析的時候爲簡單起見,全部看成爲0
                } break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    ......
                    mManager.hideFragment(f, transition, transitionStyle);
                } break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                    ......
                    mManager.showFragment(f, transition, transitionStyle);
                } break;
                case OP_DETACH: {
                    Fragment f = op.fragment;
                    ......
                    mManager.detachFragment(f, transition, transitionStyle);
                } break;
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                    ......
                    mManager.attachFragment(f, transition, transitionStyle);
                } break;
                default: {  throw new IllegalArgumentException("Unknown cmd: " + op.cmd);  } 
            }// end of switch
            op = op.next;
        } //end of while
        mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);
        .....
}
1、當前BackStackRecord存儲的所有事務的鏈表頭結點
2、這裏的op對象是之前的add()方法產生的一個事務,最終調用mManager.addFragment(f, false)方法;
往下我們會看一下FragmentManager的addFragment方法底層實現,不過我們會先看下beginTransaction()和enqueueAction()兩個方法;前者獲取FragmentTransaction對象,後者將FragmentTransaction對象交給UI線程去執行。

FragmentManagerImpl.class(FragmentManager)

final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory 
ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
ArrayList<BackStackRecord> mBackStack;
boolean mDestroyed;
FragmentHostCallback mHost; 
//提供主線程的Handler,FragmentManagerImpl所屬的Activity,在FragmentActivity的onCreate方法中會對其進行初始化
ArrayList<Runnable> mPendingActions; //需要執行的異步事務
boolean mNeedMenuInvalidate; //當前Fragment需要菜單欄
int mCurState = Fragment.INITIALIZING;//當前FragmentManager下的所有Fragment應該到達的狀態
attachController()@FragmentManager.class
public void attachController(FragmentHostCallback host, FragmentContainer container, Fragment parent) { 
        if (mHost != null) throw new IllegalStateException("Already attached");
        mHost = host;
        mContainer = container;
        mParent = parent;
}
該方法會在Fragment的onCreate方法中會被調用,主要是給mHost賦值
beginTransaction()@FragmentManager.class
public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
}
enqueueAction()@FragmentManager.class
public void enqueueAction(Runnable 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<Runnable>();  } 
            mPendingActions.add(action);
            if (mPendingActions.size() == 1) {
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
            }
        }
}
Runnable mExecCommit = new Runnable() {
        @Override
        public void run() { execPendingActions(); } //該方法內部就會將mPendingActions中的action順序調用run方法執行
};
addFragment()@FragmentManager.class
public void addFragment(Fragment fragment, boolean moveToStateNow) { //第二個參數默認是false
        if (mAdded == null) { mAdded = new ArrayList<Fragment>();}
        makeActive(fragment); //添加到mActive集合中
        if (!fragment.mDetached) {
            if (mAdded.contains(fragment)) {throw new IllegalStateException("Fragment already added: " + fragment); }
            mAdded.add(fragment); //添加到mAdded集合中
            fragment.mAdded = true;
            fragment.mRemoving = false;
            if (fragment.mHasMenu && fragment.mMenuVisible) {mNeedMenuInvalidate = true; }
            if (moveToStateNow) {moveToState(fragment);} //note1
        }
}
1、默認情況不會執行這個方法。
    在BackStackRecord的run方法最後會調用mManager.moveToState(mManager.mCurState, transition, transitionStyle, true)方法
    在FragmentManager中存在多個moveToState方法,按照參數類型個人將其分兩類,一類是參數中有Fragment的moveToState方法,另一類自然就是參數中無Fragment的moveToState方法。第一類是針對一個特定的Fragment進行操作,主要工作就是將指定的Fragment狀態轉移到FragmentManager的mCurState狀態。第二類就是更新FragmentManager的mCurState狀態!
下面先介紹不帶Fragment參數的moveToState方法。
moveToState(參數不帶Fragment)@FragmentManager.class
void moveToState(int newState, boolean always) {
        moveToState(newState, 0, 0, always);
}
void moveToState(int newState, int transit, int transitStyle, boolean always) {
        ......
        mCurState = newState; //note1
        if (mActive != null) {
            boolean loadersRunning = false;
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i); //note2
                if (f != null) {
                    moveToState(f, newState, transit, transitStyle, false);  
                    .......
                }
            }
            ......
            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
                mHost.onSupportInvalidateOptionsMenu();
                mNeedMenuInvalidate = false;
            }
        }
}
1、更新FragmentManager當前的狀態,即對mCurState賦值。
2、遍歷mActive集合中的Fragment數據並調用帶Fragment參數的moveToState方法。
    不帶Fragment參數的moveToSate方法是將FragmentManager下面的所有Fragment狀態轉移到當前FragmentManager的狀態,Fragment可能向前轉移(創建過程)也可能向後轉移(銷燬過程)。
    其實FragmentManager的參數不帶Fragment的moveToState()方法是下列方法底層實現:dispatchDestroy()、dispatchDestroyView()、dispatchStop()、dispatchPause()、dispatchResume()、dispatchStart()、dispatchActivityCreated()和dispatchCreate()方法,而這些方法會被FragmentActivity調用,如FragmentActivity的onCreate方法會調用mFragments.dispatchCreate();FragmentActivity的onStart方法會調用mFragments.dispatchActivityCreated()、mFragments.dispatchStart()兩個方法;以此類推基本都能找到在FragmentActivity對應的調用!FragmentActivity調用不帶Fragment參數的moveToState方法主要是設置當前的FragmentManager的狀態!
備註: class AppCompatActivity extends FragmentActivity,即AppCompatActivity可以使用Fragment,使用方式一樣

moveToState(參數帶Fragment)@FragmentManager.class
    下面這個方法很長,真的很很很長,可是我看嗨了(其實一開始我是拒絕的(ノへ ̄、))。。。。因爲可以說這一個方法就囊括了整個Fragment所有的生命週期、完成對用戶自定義方法的調用、將Fragment產生的視圖添加進入ViewGroup中等等,它能能滿足你對Fragment大多數的幻想。讀完你可以發現Fragment的生命週期是基於它的狀態變量!聽說在正式閱讀下面方法前,看看上面Fragment的使用,效果會更好喲~。代碼太長還有迷之縮進。。
void moveToState(Fragment f) {
        moveToState(f, mCurState, 0, 0, false);
}
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { 
        //參數值如:mManager.mCurState,0, 0, true
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {  newState = Fragment.CREATED; } 
        if (f.mRemoving && newState > f.mState) { newState = f.mState; } 
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) { newState = Fragment.STOPPED;  } 
        if (f.mState < newState) {
            ......
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    .......
                    f.mHost = mHost;
                    f.mParentFragment = mParent;
                    f.mFragmentManager = mParent != null  ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl(); 
                    f.mCalled = false;
                    f.onAttach(mHost.getContext());//note-1
                    if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f   + " did not call through to super.onAttach()");  } 
                    if (f.mParentFragment == null) {   mHost.onAttachFragment(f); } 
                    if (!f.mRetaining) {  f.performCreate(f.mSavedFragmentState); }  //note0
                    f.mRetaining = false;
                    if (f.mFromLayout) { //Fragment來自於佈局文件
                        f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), null, f.mSavedFragmentState); //note1
                        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); } 
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState); //note2
                        }
                         else {  f.mInnerView = null; } 
                    } //注意這裏沒有break!因此往下繼續執行
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                container = (ViewGroup)mContainer.onFindViewById(f.mContainerId); //note3
                                if (container == null && !f.mRestored) { throwException(new IllegalArgumentException(   "No view found for id 0x....."); } 
                            }
                            f.mContainer = container;
                            f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), container, f.mSavedFragmentState);//note4
                            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); }
                                if (container != null) {
                                    Animation anim = loadAnimation(f, transit, true,transitionStyle);//note5
                                    if (anim != null) {
                                        setHWLayerAnimListenerIfAlpha(f.mView, anim);
                                        f.mView.startAnimation(anim);
                                    }
                                    container.addView(f.mView);//note6
                                }
                                if (f.mHidden) f.mView.setVisibility(View.GONE);
                                f.onViewCreated(f.mView, f.mSavedFragmentState);//note6.5
                            }
                            else { f.mInnerView = null;}
                        }
                        f.performActivityCreated(f.mSavedFragmentState);//note7
                        if (f.mView != null) {f.restoreViewState(f.mSavedFragmentState);}
                        f.mSavedFragmentState = null;
                    } //注意這裏沒有break!因此往下繼續執行
                case Fragment.ACTIVITY_CREATED:
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) { f.performStart();} //note8
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        f.mResumed = true;
                        f.performResume(); //note9
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }//end of swith
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        f.performPause();  //note10
                        f.mResumed = false;
                    }
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {  f.performStop();} //note11
                case Fragment.STOPPED:
                    if (newState < Fragment.STOPPED) {f.performReallyStop();} //note12
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (f.mView != null) {
                            if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) { saveFragmentViewState(f);}
                        }
                        f.performDestroyView(); //note13
                        if (f.mView != null && f.mContainer != null) {
                            Animation anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
                                anim = loadAnimation(f, transit, false,transitionStyle);
                            }
                            if (anim != null) {
                                final Fragment fragment = f;
                                f.mAnimatingAway = f.mView;
                                f.mStateAfterAnimating = newState;
                                final View viewToAnimate = f.mView;
                                anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(viewToAnimate, anim) {
                                    @Override
                                    public void onAnimationEnd(Animation animation) {
                                        super.onAnimationEnd(animation);
                                        if (fragment.mAnimatingAway != null) {
                                            fragment.mAnimatingAway = null;
                                            moveToState(fragment, fragment.mStateAfterAnimating, 0, 0, false);
                                        }
                                    }
                                });
                                f.mView.startAnimation(anim);
                            }
                            f.mContainer.removeView(f.mView); //note14
                        }
                        f.mContainer = null;
                        f.mView = null;
                        f.mInnerView = null;
                    }
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        if (mDestroyed) {
                            if (f.mAnimatingAway != null) {
                                View v = f.mAnimatingAway;
                                f.mAnimatingAway = null;
                                v.clearAnimation();
                            }
                        }
                        if (f.mAnimatingAway != null) {
                            f.mStateAfterAnimating = newState;
                            newState = Fragment.CREATED;
                        }
                        else {
                            if (!f.mRetaining) { f.performDestroy();} //note15
                            f.mCalled = false;
                            f.onDetach(); //note16
                            if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f+ " did not call through to super.onDetach()"); }
                            if (!keepActive) {
                                if (!f.mRetaining) {makeInactive(f); } 
                                else {
                                    f.mHost = null;
                                    f.mParentFragment = null;
                                    f.mFragmentManager = null;
                                    f.mChildFragmentManager = null;
                                }
                            }end of if (!keepActive) 
                        }//end of else 
                    }//end of  if (newState < Fragment.CREATED) 
            }//end of switch
        }//end of  else if (f.mState > newState) 
        f.mState = newState; //17
}//end of function
-1、onAttach(Context context)
0、onCreate(savedInstanceState)
下面的第1-2步是針對當前Fragment位於一個View Layout裏面的情況,即靜態而非動態使用Fragment的情況
1、onCreateView(inflater, container, savedInstanceState);
2、onViewCreated(View view, @Nullable Bundle savedInstanceState)
下面的3-6.5是動態使用Fragment的情況
3、獲得該Fragment所屬的ViewGroup
4、onCreateView(inflater, container, savedInstanceState);
5、載入動畫
6、將Fragment獲得的View添加到第三步得到的ViewGroup中
6.5、onViewCreated(View view, @Nullable Bundle savedInstanceState)
7、onActivityCreated(savedInstanceState);
8、onStart();
9、onResume();
10、onPause();
11、onStop();
13、onDestroyView();
14、將當前View從ViewGroup中移除出去
15、onDestroy();
16、onDetach()
17、更新參數Fragment的狀態和FragmentManager的狀態相同
    通過對該方法的分析,我們得出FragmentManager通過調用Fragment對象相關方法,使得Fragment狀態最終轉移到和FragmentManager相同的狀態。具體狀態分爲Initial、Created、ActivityCreated、Stopped、Start、Resume共6個狀態。預期狀態(newState)大於Fragment自身的狀態(f.mState < newState)則將Fragment的狀態向前推進即下圖的左邊方向,對應Fragment的創建過程;預期狀態(newState)小於Fragment自身的狀態(f.mState > newState)則將Fragment的狀態向後推進即下圖的右邊方向,對應Fragment的銷燬過程;
    其實FragmentManager中帶Fragment參數的moveToState方法是下列方法底層實現:detachFragment、attachFragment、removeFragment、addFragment等方法,這些方法不會在FragmentActivity中出現,但是會在FragmentTransaction中的run方法中出現,即每次提交的事務最終會調用這些方法完成實際的Fragment的加載與銷燬















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章