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.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已经存在。对于常用的
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: