1、添加/替换fragment视图有两种方法
getSupportFragmentManager().beginTransaction()
.replace(R.id.contain,new
和
getSupportFragmentManager().beginTransaction()
.add(R.id.contain,new
replace相当于remove+add所以会将原来fragment销毁掉(视图销毁+fragment销毁)
add只是添加到容器不会销毁视图和fragment对象。add配合hidden和show使用,可以在app首页用于tab切换这样不会像replace那样来回切换销毁视图销毁fragment,重建fragment对系统开销大。
但是如果fragment添加了回退栈setBackStack(null)在使用replace方法时,这个时候视图会销毁但是fragment对象不会销毁。
2、FragmentPageAdapter与FragmentStatePageAdapter区别
当Fragment和Viewpager一起使用的时候时,Viewpager默认保存3个fragment对象(即当前,当前左,当前右),当滑动超过第三个时如果adapter是FragmentPageAdapter第一个Fragment的视图会销毁(对象不会销毁);如果adapter是FragmentStatePageAdapter时第一个Frament视图和对象都销毁。
故Fragment比较少的时候(比如只有3,4个)选取viewpager+FragmentPagerAdapter的组合,当fragment比较多(大于3,4个)这个时候选取viewpager+FragmentStatePagerAdapter的方式来实例化fragment。
3、修改viewpage默认保存fragment保存个数用viewpage.setOffscreenPageLimit(int count)方法
4、Fragment添加了回退栈setBackStack(null)进入新的Frament,在新的fragment里面想返回到之前Fragment可以用getSupportFragmentManager().popBackStack()方法
5、Fragment的getActivity()为null,解决办法
可能你遇到过getActivity()返回null,或者平时运行完好的代码,在“内存重启”之后,调用getActivity()的地方却返回null,报了空指针异常。
大多数情况下的原因:你在调用了getActivity()时,当前的Fragment已经onDetach()了宿主Activity。
比如:你在pop了Fragment之后,该Fragment的异步任务仍然在执行,并且在执行完成后调用了getActivity()方法,这样就会空指针。
解决办法:
更"安全"的方法:(对于Fragment已经onDetach这种情况,我们应该避免在这之后再去调用宿主Activity对象,比如取消这些异步任务,但我们的团队可能会有粗心大意的情况,所以下面给出的这个方案会保证安全)
在Fragment基类里设置一个Activity mActivity的全局变量,在onAttach(Activity activity)里赋值,使用mActivity代替getActivity(),保证Fragment即使在onDetach后,仍持有Activity的引用(有引起内存泄露的风险,但是异步任务没停止的情况下,本身就可能已内存泄漏,相比Crash,这种做法“安全”些),即:
protected Activity mActivity;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = activity;
}
/**
* 如果你用了support 23的库,上面的方法会提示过时,
有强迫症的小伙伴,可以用下面的方法代替
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (Activity)context;
}
6、Fragment重叠异常-----正确使用hide、show的姿势
如果你add()了几个Fragment,使用show()、hide()方法控制,比如微信、QQ的底部tab等情景,如果你什么都不做的话,在“内存重启”后回到前台,app的这几个Fragment界面会重叠。
原因是FragmentManager帮我们管理Fragment,当发生“内存重启”,他会从栈底向栈顶的顺序一次性恢复Fragment;
但是因为没有保存Fragment的mHidden属性,默认为false,即show状态,所以所有Fragment都是以show的形式恢复,我们看到了界面重叠。
(如果是replace,恢复形式和Activity一致,只有当你pop之后上一个Fragment才开始重新恢复,所有使用replace不会造成重叠现象)
解决方案:可以给给一个fragment添加默认白色背景
还有一种场景,add和replace都有可能造成重叠: 在onCreate中加载Fragment,并且没有判断saveInstanceState==null,导致重复加载了同一个Fragment导致重叠。(PS:replace情况下,如果没有加入回退栈,则不判断也不会造成重叠,但建议还是统一判断下)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 在页面重启时,Fragment会被保存恢复,而此时再加载Fragment会重复加载,导致重叠 ;
if(saveInstanceState == null){
// 正常情况下去 加载根Fragment
}
}
7、Fragment与Activity之间的交互
Fragment与Activity之间的交互可以通过Fragment.setArguments(Bundle args)以及Fragment.getArguments()来实现。
8、Fragment状态的持久化。
由于Activity会经常性的发生配置变化,所以依附它的Fragment就有需要将其状态保存起来问题。下面有两个常用的方法去将Fragment的状态持久化。
•方法一:可以通过protected void onSaveInstanceState(Bundle outState),protected void onRestoreInstanceState(Bundle savedInstanceState) 状态保存和恢复的方法将状态持久化。
•方法二:(更方便,让Android自动帮我们保存Fragment状态):
我们只需要将Fragment在Activity中作为一个变量整个保存,只要保存了Fragment,那么Fragment的状态就得到保存了。
◾FragmentManager.putFragment(Bundle bundle, String key, Fragment fragment)
是在Activity中保存Fragment的方法。
◾FragmentManager.getFragment(Bundle bundle, String key)
是在Activity中获取所保存的Frament的方法。
Key就传入Fragment的id,Fragment就是你要保存状态的fragment,但我们注意到上面的两个方法,第一个参数都是Bundle,这就意味着FragmentManager是通过Bundle去保存Fragment的。但是,这个方法仅仅能够保存Fragment中的控件状态,比如说EditText中用户已经输入的文字(注意!在这里,控件需要设置一个id,否则Android将不会为我们保存控件的状态),而Fragment中需要持久化的变量依然会丢失,但依然有解决办法,就是利用方法一!
下面给出状态持久化的事例代码:
/** Activity中的代码 **/
FragmentB fragmentB;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_activity);
if( savedInstanceState != null ){
fragmentB = (FragmentB) getSupportFragmentManager().getFragment(savedInstanceState,"fragmentB");
}
init();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
if( fragmentB != null ){
getSupportFragmentManager().putFragment(outState,"fragmentB",fragmentB);
}
super.onSaveInstanceState(outState);
}
/** Fragment中保存变量的代码 **/
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
AppLog.e("onCreateView");
if ( null != savedInstanceState ){
String savedString = savedInstanceState.getString("string");
//得到保存下来的string
}
View root = inflater.inflate(R.layout.fragment_a,null);
return root;
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("string","anAngryAnt");
super.onSaveInstanceState(outState);
}