您的当前位置:首页正文

Fragment注意事项总结

来源:要发发知识网
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);
   }