Fragment
概念
Android从3.0之后引入了Fragment,可以把它理解为页面的一个片段,比如一个html网页就包含一个header头部片段,以及一个body身体片段。
设计Fragment的目的是让页面布局更加灵活,不但可以随意组装和拼接各个片段,还可以只更新某个片段实现页面局部更新的功能(这个类似网页的ajax技术)。Fragment可以协助我们完成如下任务:
1、在一个页面中嵌入多个连续可翻页的子视图,方面使用ViewPager统一管理;
2、开发一些通用的小部件,内部封装好代码逻辑,可直接嵌入到任意页面。比如广告、地图等组件;
3、同一套代码可适配不同尺寸的屏幕,比如说同时适配竖屏与横屏,同时适配手机与平板等等;
动态注册
Fragment有两种使用方式,一种是动态注册,另一种是静态注册。
动态注册指的是在代码中动态给当前页面加上Fragment,该方式主要用于一个Activity存在多个子页面的情况。因为存在多个页面,且页面数量可变化,所以只能在代码中进行注册。
常见的Fragment动态注册都与ViewPager结合使用,先写好Fragment页面的代码;然后定义一个基于FragmentStatePagerAdapter的适配器,该适配器从一个FragmentManager对象构造而来,每个元素返回的又是已初始化的Fragment对象;最后对ViewPager设置该适配器,从而把ViewPager与多个Fragment页面关联起来。
若想给Fragment传递参数,可在Fragment类中定义一个静态方法newInstance,在该方法中通过setArguments函数写入Bundle对象;然后重写方法onCreateView,在该方法中通过getArguments函数取出Bundle对象。这样,每次获取Fragment实例,都是调用newInstance方法获得,而不是调用它的构造函数。
静态注册
静态注册指的是Fragment一旦定义好,就能在布局文件中通过fragment节点直接嵌入子页面的情况。静态注册主要用于多个Activity共享一个子页面,比如说顶部广告、底部推广、嵌入地图等等,最常见的是百度地图SDK的运用,app要想在页面上展示百度地图,只需在布局中加上一个百度地图的fragment即可。
下面是在布局文件中静态注册fragment的一个例子:
<fragment
android:id="@+id/fragment_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.example.exmfragment.fragment.StaticFragment" />
静态注册需要注意如下几点:
1、fragment节点必须指定id属性,不然运行app会报错;
2、代码中Fragment必须import自“android.app.Fragment”,不能使用“android.support.v4.app.Fragment”,不然运行app会报错“Trying to instantiate a class *** that is not a Fragment”;
可能大家发现静态注册跟自定义控件比较类似,都是定义好一个局部界面,然后在布局中加入自定义标记。虽然原理类似,但是Fragment比起自定义控件有如下优势:
1、自定义控件内部一般不直接处理业务逻辑,相反Fragment经常处理业务逻辑;
2、自定义控件生成画面后,要再更新该控件画面,只能从外部Activity强行刷新该控件;但Fragment自身就能处理局部页面更新,无需外部来通知;
3、自定义控件无生命周期管理,Fragment有生命周期管理。
两种注册方式的区别
下面是动态注册与静态注册在写代码时候的区别:
1、动态注册的页面必须继承自FragmentActivity,因为在构造适配器时需要调用getSupportFragmentManager方法,来获得FragmentManager对象;而静态注册的页面只需继承自Activity。
2、动态注册的Fragment导入的是“android.support.v4.app.Fragment”;而静态注册只能导入“android.app.Fragment”,否则运行时会报错。
3、动态注册可以在构造Fragment时传入参数,而静态注册无法直接传参。
Fragment进阶
竖屏与横屏的兼容
前面我们说到,Fragment可用于切换不同尺寸的屏幕,为了实现这个功能,Android引入了碎片事务FragmentTransaction。该事务的对象可从FragmentManager的beginTransaction方法获得,下面是FragmentTransaction的常用方法:
add : 添加碎片
replace : 替换碎片。无则添加,有则替换
remove : 移除碎片
addToBackStack : 加入一个回退栈。这是为了在用户按下返回键时,能够回到上一个页面。
commit : 提交事务
commitAllowingStateLoss : 提交事务时允许状态丢失。导致状态丢失的情况有很多,其中一种是早期的Android可能在onStop之前就会结束Activity,后来从3.0开始只能在onStop之后才能结束Activity,这样早期Android如果在omPause与onStop之间执行commit方法,就可能扔出状态丢失的异常。那么commitAllowingStateLoss方法便是兼容的做法,即使状态丢失也允许提交,但这其实是不安全的做法,要避免不安全的情况发生,得注意以下几点:
1、不要在onResume中调用commit方法,因为此时可能状态尚未恢复;
2、不要往Fragment传递较大的参数,比如说图像数据;
3、不要在异步任务中调用commit方法;
竖屏与横屏切换的开发注意事项如下,手机与平板的切换可参照处理:
1、横屏的布局文件放在目录layout-land,竖屏的布局文件根节点采用FrameLayout,横屏的布局文件根节点采用LinearLayout(水平排列)。
2、代码中需要判断当前界面是横屏还是竖屏,然后补充相应的处理逻辑,例如竖屏时切换页面要增加“fragmentTrs.addToBackStack(null);”,这是模拟按下返回键时回到上个页面。
3、竖屏的页面切换后,因为根节点是FrameLayout,所以上一页面只是界面被覆盖了,可是点击事件这些都还在。因此为了避免触摸当前页面导致触发上一页面的点击事件,需要在页面切换时禁用上一页面的相关控件,当然返回到上一页面时就得开启相关控件。
Fragment的生命周期
Fragment的生命周期参照Activity(参见《 Android开发笔记(三十九)Activity的生命周期》),同时多出了几个方法,具体说明如下:
onAttach : 关联Fragment与Activity,在onCreate之前调用。可在该方法实例化Activity的一个回调对象,就能在Fragment中调用Activity的回调方法,这样设计的好处是Activity无需调用set***Listener方法来设置监听器接口。
onCreateView : 创建Fragment的视图,在onCreate之后调用。
onActivityCreated : 在Activity页面创建完毕之后调用,这意味着onCreateView有可能在主页面尚未创建完毕时就完成了,比如说在主页面的onCreate方法中加入Fragment。
onDestroyView : 结束Fragment的视图,在onDestroy之前调用。
onDetach : 取消关联Fragment与Activity,在onDestroy之后调用。
Fragment的子类
Android还给Fragment设计了几个子类,分别用在某些特殊的场合,具体说明如下:
DialogFragment : 用于对话框的碎片。参见《 Android开发笔记(二十三)文件对话框FileDialog》,对话框页面逻辑要写在onCreateDialog方法中,另外DialogFragment也实现了Dialog的常见方法。
ListFragment : 用于列表的碎片,用法类似ListActivity。
PreferenceFragment : 用于设置页面的碎片。比如Android自带的“系统设置”app就使用了PreferenceFragment。
WebViewFragment : 用于WebView的碎片。
代码示例
限于篇幅,这里就不一一贴出代码例子了,有需要的朋友可在评论中留下你的邮箱,我看到后把示例工程发过去。
点此查看Android开发笔记的完整目录