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、提交操作
ok,操作基本结束。下面我们详细讨论下这个过程。ft.commit();
获取Fragment实例
在获取Fragment实例过程中。通常要注意以下几点:
1、参数传递:
建议使用
setArguments()方法进行传递。因为我们知道在旋转设备或者程序意外退出等会调用
Activity中的onSaveInstanceState()方法 来保存信息。当Activity重新启动时保存的数据通过onCreate方法中的参数Bundle来恢复,对于其内部的Fragment则通过反射无参构造器来实例化一个新的Fragment。 当我们通过重载构造器传递参数或通过setter方法传递参数,在恢复当前Fragment时常引起不必要的麻烦。 然而通过setArguments()方法设置的相关参数,Fragment会自动为我们保存。首先我们分析下数据的保存。 保存数据时调用
FragmentActivity的onSaveInstanceState()方法。/** * 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); } }在该方法中调用
FragmentManager的saveAllState()方法,将其返回的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类的代码可以发现成员变量mActive是FragmentState类型的数组。final class FragmentManagerState implements Parcelable { FragmentState[] mActive; ... }此刻我们就明白了在保存数据时会通过
FragmentActivity的onSaveInstanceState方法, 将当前活动的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); } ... }在这个方法内部会调用
FragmentManager的restoreAllState方法。并在这个方法的内部通过调用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.instantiatepublic 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已经存在。对于常用的
findFragmentById或findFragmentByTag均首先从当前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是否作为另一个Fragment的child,如果是则返回这个父Fragment的getChildFragmentManager,如果不是则返回activity的FragmentManager. 官方介绍如下:/** * 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){ ... } ... }
- mActivity.getSupportFragmentManager
返回当前FragmentActivity中的
FragmentTransaction:
- replace、remove、add、addBackStack:
- commit: