Fragment是嵌套入Activity的片段,比Activity要更为轻巧灵活,但是用起来也会相对比较麻烦一些。之前在学习Fragment和实际开发中遇到一些Fragment的问题,所以就这些问题进行了整理。
一、Fragment的初始化
Google源码中一般采用newInstance的静态方法来新建一个fragment,建议用setArgument的方式来传递参数,将所需的参数直接暴露出来,方便一起开发的同事知道需要传什么数据。

二、屏幕旋转带来的问题
1、配置如下属性,限制Fragment托管的Activity旋转
<activity android:name= ".MainActivity"
android:configChanges = "orientation|screenSize">
2、保留Fragment
用setRetainInstance(true)方法保留fragment实例。fragment的retainInstance属性值默认是false,表明fragment默认不会被保留。在屏幕旋转时,fragment的托管activity会被销毁重建,FragmentManager会销毁队列中的fragment视图,接着会检查retainInstance属性,如果属性是false(默认值),FragmentManager就会销毁该fragment。如果为true,该fragment的视图会被销毁,fragment本身并不销毁,新的FragmentManager会找到它,并给他创建新视图。但是,如果系统因为内存不足而销毁了托管的Activity,被保留的Fragment也会被销毁。

3、savedInstanceState
在Activity中我们可以通过onSaveInstanceState()方法和onRestoreInstanceState()方法实现数据的存储。

Fragment的保存机制和Activity类似,不过FragmentmyonRestoreInstanceState()方法,需要在onActivityCreated()中实现。

4、View的保存
在视图被销毁之后如果想要保存View的state,需要实现onSaveInstanceState()方法和onRestoreInstanceState()方法。安卓自带的View一般已经实现了这个方法,开发者在使用的时候只需要添加android:freezeText=”true”属性。
关于Fragment的保存,一篇外国博文做了较为详细的介绍。The Real Best Practices to Save/Restore Activity's and Fragment's state. (StatedFragment is now deprecated)
三、FragmentTransaction 的 add和remove、show和hide、replace的使用
transaction.add()
往Activity中添加一个Fragment
transaction.remove()
从Activity中移除一个Fragment,如果被移除的Fragment在没有添加到回退栈的情况下,这个Fragment实例将会被销毁。
transaction.replace()
使用另一个Fragment替换当前的。
transaction.hide()
隐藏当前的Fragment
transaction.show()
显示之前隐藏的Fragment
替换fragment
使用replace切换:
使用replace切换回调用一下2段life cycle
05-08 07:44:30.554 2864-2864/? D/_Albert: FirstFragment:onAttch
05-08 07:44:30.554 2864-2864/? D/_Albert: FirstFragment:onCreate
05-08 07:44:30.554 2864-2864/? D/_Albert: FirstFragment:onCreateView
05-08 07:44:30.561 2864-2864/? D/_Albert: FirstFragment:onActivityCreated
05-08 07:44:30.561 2864-2864/? D/_Albert: FirstFragment:onStart
05-08 07:44:30.561 2864-2864/? D/_Albert: FirstFragment:onResume
05-08 07:44:43.010 2864-2864/? D/_Albert: FirstFragment:onPause
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onStop
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onDestoryView
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onDestory
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onDetach
05-08 07:44:43.011 2864-2864/? D/_Albert: ReplaceFragment:onAttch
05-08 07:44:43.011 2864-2864/? D/_Albert: ReplaceFragment:onCreate
05-08 07:44:43.011 2864-2864/? D/_Albert: ReplaceFragment:onCreateView
05-08 07:44:43.015 2864-2864/? D/_Albert: ReplaceFragment:onActivityCreated
05-08 07:44:43.015 2864-2864/? D/_Albert: ReplaceFragment:onStart
05-08 07:44:43.016 2864-2864/? D/_Albert: ReplaceFragment:onResume
也就是说,replace会remove掉之前的fragment,再将替换fragment,add进去。
使用add、show、hide切换:
life cycle 如下:
05-08 08:16:44.818 3740-3740/? D/_Albert: FirstFragment:onAttch
05-08 08:16:44.819 3740-3740/? D/_Albert: FirstFragment:onCreate
05-08 08:16:44.819 3740-3740/? D/_Albert: FirstFragment:onCreateView
05-08 08:16:44.824 3740-3740/? D/_Albert: FirstFragment:onActivityCreated
05-08 08:16:44.825 3740-3740/? D/_Albert: FirstFragment:onStart
05-08 08:16:44.825 3740-3740/? D/_Albert: FirstFragment:onResume
05-08 08:16:55.383 3740-3740/? D/_Albert: SecondFragmentonAttch
05-08 08:16:55.383 3740-3740/? D/_Albert: SecondFragmentonCreate
05-08 08:16:55.383 3740-3740/? D/_Albert: SecondFragmentonCreateView
05-08 08:16:55.384 3740-3740/? D/_Albert: SecondFragment:onActivityCreated
05-08 08:16:55.384 3740-3740/? D/_Albert: SecondFragment:onStart
05-08 08:16:55.384 3740-3740/? D/_Albert: SecondFragment:onResume
以上生命周期的对比表明replace方法会remove之前的fragment,而用add搭配hide方法只是将之前的fragment做一个隐藏,并不会触发他的life cycle。在实际开发中,如果要保留一面用户操作界面的建议不要采用replace方法去切换。
四、getActivity为null的坑
Fragment中的Context的我们一般利用getActivity()来获取托管的Activity()作为Context使用。
而getActivity有时会null。
一种做法是保持对Activity的引用。
@Override
public voidonAttach(Activity activity) {
super.onAttach(activity);
mContext= activity;
}
getActivity()==null一般出现在Fragment和Activity没有关联的情况。较为稳妥的做法是找到没关联的原因。如果确定已经onAttach()过了,问题大多出现在onDetach()里面。原因可能是托管的Activity已经被销毁。或者Fragment的实例被删去之后View没有被赋值mContainerView,导致UI一直在。
网友评论