Fragment小结

通常我们使用Fragment基本过程如下:

  • 1、首先我们得有一个Fragment实例
    Fragment fragment = new Fragment();
    
  • 2、获取FragmentManger
    FragmentManager fm = get**FragmentManager();
    
  • 3、获取事务FragmentTransaction
    FragmentTransaction ft = fm.beginTransaction();
    
  • 4、对目标Fragment进行操作
    ft.replace(contaninerId,fragment);
    
  • 5、提交操作
    ft.commit();
    
    ok,操作基本结束。下面我们详细讨论下这个过程。

获取Fragment实例

在获取Fragment实例过程中。通常要注意以下几点:

  • 1、参数传递:

    建议使用setArguments()方法进行传递。

    因为我们知道在旋转设备或者程序意外退出等会调用Activity中的onSaveInstanceState()方法 来保存信息。当Activity重新启动时保存的数据通过onCreate方法中的参数Bundle来恢复,对于其内部的Fragment则通过反射无参构造器来实例化一个新的Fragment。 当我们通过重载构造器传递参数或通过setter方法传递参数,在恢复当前Fragment时常引起不必要的麻烦。 然而通过setArguments()方法设置的相关参数,Fragment会自动为我们保存。

    • 首先我们分析下数据的保存。 保存数据时调用FragmentActivityonSaveInstanceState()方法。

      /**
      * Save all appropriate fragment state.
      */
      @Override
      protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
      }
      

      在该方法中调用FragmentManagersaveAllState()方法,将其返回的Parcelable类型的对象保存在Bundle类型对象中。

      FragmentManager.saveAllState()代码如下:

      Parcelable saveAllState() {
        ...
        // First collect all active fragments.
        int N = mActive.size();
        FragmentState[] active = new FragmentState[N];
        ...
        FragmentManagerState fms = new FragmentManagerState();
        fms.mActive = active;
        ...
        return fms;
      }
      

      FragmentManager.saveAllState()中会创建一个FragmentState类型的数组。然后将其赋值给FragmentManagerState类型的的成员变量mActive

      FragmentState是什么呢?继续查看代码:

      final class FragmentState implements Parcelable {
            ...
        final Bundle mArguments;
            ...
        public FragmentState(Fragment frag) {
                ...
            mArguments = frag.mArguments;
        }
      
        public FragmentState(Parcel in) {
                ...
            mArguments = in.readBundle();
                ...
        }
            ...
      }
      

      通过FragmentState类的源码得知FragmentManager.saveAllState()中会把当前活动的Fragment通过FragmentState的构造函数传递进去,并将每个Fragment的成员变量mArguments赋值给FragmentState的成员变量mArguments.

      通过查看FragmentManagerState类的代码可以发现成员变量mActiveFragmentState类型的数组。

      final class FragmentManagerState implements Parcelable {
        FragmentState[] mActive;
        ...
      }
      

      此刻我们就明白了在保存数据时会通过FragmentActivityonSaveInstanceState方法, 将当前活动的Fragment中通过setArguments设置的参数保存下来。

    • 数据的恢复:

      FragmentActivity中的onCreate代码:

      /**
      * Perform initialization of all fragments and loaders.
      */
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        ...
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        ...
      }
      

      在这个方法内部会调用FragmentManagerrestoreAllState方法。并在这个方法的内部通过调用FragmentState中的instantiate方法获取一个Fragment。

      void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
        ...
            ...
                //fs 为FragmentState类型
                Fragment f = fs.instantiate(mActivity, mParent);
            ...
        ...
      }
      

      FragmentState中,会实例化保存的相关数据其中就有通过setArguments()设置的参数。同时还会通过Fragment.instantiate方法反射无参构造器来实例化一个新的Fragment。 FragmentState.instantiate中:

      public Fragment instantiate(FragmentActivity activity, Fragment parent) {
        ...
        //实例化保存的mArguments数据
        if (mArguments != null) {
            mArguments.setClassLoader(activity.getClassLoader());
        }
      
        mInstance = Fragment.instantiate(activity, mClassName, mArguments);
      
        ...
      
      }
      

      Fragment.instantiate

      public static Fragment instantiate(Context context, String fname, Bundle args) {
        try{
            Class<?> clazz = sClassMap.get(fname);
            if (clazz == null) {
                // Class not found in the cache, see if it's real, and try to add it
                clazz = context.getClassLoader().loadClass(fname);
                sClassMap.put(fname, clazz);
            }
            Fragment f = (Fragment)clazz.newInstance();
            if (args != null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.mArguments = args;
            }
            return f;
        }
            ...
            ...
      }
      
  • 2、避免重复创建对象

    • 在进行Fragment事务操作时要在Fragment堆栈里面看看是否当前fragment已经存在。对于常用的findFragmentByIdfindFragmentByTag均首先从当前FragmentManager中的活动Fragmentlist中查找,没有找到则从Addedlist中查找。

      public Fragment findFragmentById(int id){
          if (mAdded != null) {
            // First look through added fragments.
            for (int i=mAdded.size()-1; i>=0; i--) {
                Fragment f = mAdded.get(i);
                if (f != null && f.mFragmentId == id) {
                    return f;
                }
            }
        }
        if (mActive != null) {
            // Now for any known fragment.
            for (int i=mActive.size()-1; i>=0; i--) {
                Fragment f = mActive.get(i);
                if (f != null && f.mFragmentId == id) {
                    return f;
                }
            }
        }
        return null;
      }
      
      public Fragment findFragmentByTag(String tag){
        if (mAdded != null && tag != null) {
            // First look through added fragments.
            for (int i=mAdded.size()-1; i>=0; i--) {
                Fragment f = mAdded.get(i);
                if (f != null && tag.equals(f.mTag)) {
                    return f;
                }
            }
        }
        if (mActive != null && tag != null) {
            // Now for any known fragment.
            for (int i=mActive.size()-1; i>=0; i--) {
                Fragment f = mActive.get(i);
                if (f != null && tag.equals(f.mTag)) {
                    return f;
                }
            }
        }
        return null;
      }
      
      public Fragment findFragmentByWho(String who){
        if (mActive != null && who != null) {
            for (int i=mActive.size()-1; i>=0; i--) {
                Fragment f = mActive.get(i);
                if (f != null && (f=f.findFragmentByWho(who)) != null) {
                    return f;
                }
            }
        }
        return null;
      }
      
  • 3、在布局文件中直接声明Fragment的意义

Fragment事务

  • 获取FragmentManager实例:

    • mActivity.getSupportFragmentManager 返回当前FragmentActivity中的FragmentManager类型的mFragments.这个对象在声明时被初始化。
        public class FragmentActivity extends Activity {
                ...
                final FragmentManagerImpl mFragments = new FragmentManagerImpl();
                ...
        }
      
    • mFragment.getFragmentManager(): 这个方法通常首先查看当前Fragment是否作为另一个Fragmentchild,如果是则返回这个父FragmentgetChildFragmentManager,如果不是则返回activityFragmentManager. 官方介绍如下:

        /**
        * Return the FragmentManager for interacting with fragments associated
        * with this fragment's activity.  Note that this will be non-null slightly
        * before {@link #getActivity()}, during the time from when the fragment is
        * placed in a {@link FragmentTransaction} until it is committed and
        * attached to its activity.
        *
        * <p>If this Fragment is a child of another Fragment, the FragmentManager
        * returned here will be the parent's {@link #getChildFragmentManager()}.
        */
      final public FragmentManager getFragmentManager() {
        return mFragmentManager;
      }
      

      Fragment初始化时给当前FragmentManager赋值:

        void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
                ...
                if(f.mState < newState){
                    ...
                    switch(f.mState){
                        case Fragment.INITIALIZING:
                        ...
                        f.mParentFragment = mParent;
                        f.mFragmentManager = mParent != null
                            ? mParent.mChildFragmentManager : mActivity.mFragments;
                        ...
      
                    }
      
                }else if(f.state > newState){
                    ...
                }
                ...
            }
      
  • FragmentTransaction:

  • replace、remove、add、addBackStack:
  • commit:

Fragment生命周期

results matching ""

    No results matching ""