美文网首页Android
Fragment深入学习

Fragment深入学习

作者: evan_man | 来源:发表于2016-05-05 20:42 被阅读618次

    本节将对Fragment进行学习和探究,了解底层原理。通过一个简单的使用范例为入口,层层深入最终分析出FragmentActivity、FragmentTransaction、FragmentManager类之间方法如何调用,对象如何创建,Fragment生命周期如何实现等等问题。通过具体的分析得出结论如下:

    • 在FragmentManager中存在多个moveToState方法,按照参数类型个人将其分两类,一类是参数中有Fragment的moveToState方法,另一类自然就是参数中无Fragment的moveToState方法。第一类是针对一个特定的Fragment进行操作,主要工作就是将指定的Fragment状态转移到FragmentManager的mCurState状态。第二类就是更新FragmentManager的mCurState状态!
    • Fragment状态分为Initial、Created、ActivityCreated、Stopped、Start、Resume共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布局文件(方法如下)

    1.png 3.png
    <?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。对于该部分感兴趣的同学可以参考博客http://blog.csdn.net/flowingflying/article/details/6631132

    创建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>
    

    上述代码实现了大体如下的功能:

    更多资料参考:https://guides.codepath.com/android/Creating-and-Using-Fragments

    源码分析##

    下面的分析是以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, OnCreateContextMen uListener

    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

    Fields####

    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()、dispatch Pause()、dispatchResume()、dispatchStart()、dispatchActivity Created() 和dispatchCreate()方法,而这些方法会被FragmentActivity调用,如FragmentActivity的onCreate方法会调用mFragments.dispatchCreate();FragmentActivity的onStart方法会调用mFragments.dispatchActivityCreated()、mFragments.dispatchStart()两个方法;以此类推基本都能找到在FragmentActivity对应的调用!FragmentActivity调用不带Fragment参数的moveToState方法主要是设置当前的FragmentManager的状态!
    备注: class AppCompatActivity extends FragmentActivity,即AppCompat Activity可以使用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的加载与销毁。

    4.png

    相关文章

      网友评论

        本文标题:Fragment深入学习

        本文链接:https://www.haomeiwen.com/subject/bswdrttx.html