码迷,mamicode.com
首页 > 其他好文 > 详细

Fragment深入学习

时间:2016-05-06 12:37:44      阅读:362      评论:0      收藏:0      [点我收藏+]

标签:

    本节将对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对象内部结构。

HostCallbacks.class@FragmentActivity.class 

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的加载与销毁
技术分享














Fragment深入学习

标签:

原文地址:http://blog.csdn.net/evan_man/article/details/51329320

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!