Fragment是嵌套入Activity的片段,比Activity要更为轻巧灵活,但是用起来也会相对比较麻烦一些。之前在学习Fragment和实际开发中遇到一些Fragment的问题,所以就这些问题进行了整理。
一、Fragment的初始化
Google源码中一般采用newInstance的静态方法来新建一个fragment,建议用setArgument的方式来传递参数,将所需的参数直接暴露出来,方便一起开发的同事知道需要传什么数据。
二、屏幕旋转带来的问题
1、配置如下属性,限制Fragment托管的Activity旋转
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一直在。