1、Fragment简介
Android 3.0(API 11)添加了一个强大的功能就是 Fragment (片段),主要是为了给大屏幕(如平板电脑)提供更加动态和灵活的 UI 设计支持。
2、Fragment分类
现在,Google有两个版本的fragment实现可供选择:原生版本和支持库版本。
原生版本的Fragment来自系统库(android.app.Fragment)
支持库版的Fragment来自AppCompat库( android.support.v4.app.Fragment)
原生版本的fragment实现内置在设备系统中。如果应用要支持各个系统版本,在不同设备上运行的fragment可能会有不同的表现。(这主要是因为各个版本的维护有差异,例如,某个bug在4.4系统版本里已修正,而在4.0里却没有。)支持库版本的fragment在类库里,发布时,会打包在应用里。显然,使用支持库fragment的应用,无论在哪台设备上运行,都会有相同的表现。
应坚持使用支持库版的fragment,支持库版fragment使用最方便。任何时候,只要想升级支持库版fragment的话,只需要下载升级包,重新编译发布一个新版本应用就行了。Google每年会多次更新支持库,并借此引入新特性、修复bug。要享受这些好处,升级应用的支持库版本就行了。
3、Fragment功能
采用fragment而不是activity来管理应用UI,可绕开Android系统activity使用规则的限制。fragment是一种控制器对象,activity可委派它执行任务。这些任务通常就是管理用户界面。受管的用户界面可以是一整屏或是整屏的一部分。
管理用户界面的fragment又称为UI fragment。它自己也有产生于布局文件的视图。fragment视图包含了用户可以交互的可视化UI元素。activity视图能预留位置供fragment视图插入。如果有多个fragment要插入,activity视图就提供多个位置。
fragment本身没有在屏幕上显示视图的能力。因此,只有将它的视图放置在activity的视图层级结构中,fragment视图才能显示在屏幕上。
4、从Activity角度看Fragment
从上面看到,Activity需要委托Fragment帮忙管理界面。
为托管UI fragment,activity必须:
(1)在其布局中为fragment的视图安排位置;
(2) 管理fragment实例的生命周期。
5、Fragment的生命周期
下图展示了Fragment的生命周期,类似于activity的生命周期,它具有停止、暂停以及运行状态,也拥有可以覆盖的方法,用来在关键节点完成一些任务。可以看到,许多方法对应着activity的生命周期方法。
关键区别
fragment的生命周期方法由托管的activity调用而不是操作系统调用。操作系统不关心activity怎么处理用来管理视图的fragment。fragment的使用是activity内部的事情。
6、Activity托管Fragment的两种方式
activity托管UI fragment有如下两种方式:
(1) 在activity布局中添加fragment;
(2) 在activity代码中添加fragment。
(1)------第一种方式就是使用布局fragment。这种方式简单但不够灵活。在activity布局中添加fragment,就等同于将fragment及其视图与activity的视图绑定在一起,并且在activity的生命周期过程中,无法替换fragment视图。
(2)------第二种方式比较复杂,但也是唯一可以动态控制fragment的方式。何时添加fragment以及随后可以完成何种具体任务由你自己定;也可以移除fragment,用其他fragment代替当前fragment,然后重新添加已移除的fragment。
因而,为追求真正灵活的UI设计,就必须通过代码的方式添加fragment
7、Fragment如何创建视图
片段在自己的 onCreateView() 方法中创建一个视图并返回,方法签名如下
public View onCreateView(LayoutInflater inflater , ViewGroup container , Bundle savedInstanceState)
-
container为托管该fragment的Activity,
-
inflater用来将视图填充到该fragment中
通常用它的inflate(int resId , ViewGroup container, boolean attachToRoot)
方法
resId为待扩展布局的资源Id,container为托管该fragment的Activity
attachToRoot表示是否在扩展期间将扩展布局插入ViewGroup,通常是false,因为通常是通过代码的方式动态的插入到ViewGroup。 -
Bundle用来保存之前的状态信息
8、如何在Activity中使用Fragment
通常是在Activity的onCreate()方法中做如下操作
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);
if (fragment == null){
fragment = createFragment();
fragmentManager.beginTransaction()//return FragmentTransaction
.add(R.id.fragment_container,fragment) //return FragmentTransaction
.commit();//Returns the identifier of this transaction's back stack entry
}
在 Activity 中通过使用 FragmentManager 来管理fragment,通过调用 getFragmentManager() 或者 getSupportFragmentManager() 来获取 FragmentManager 的实例。
然后,在 FragmentManager 调用 beginTransaction() 方法来获取 FragmentTransaction 对象,从而得以执行fragment事务(如添加、移除或替换fragment)。
FragmentManager的功能如下:
FragmentManager类具体管理:
- fragment队列;
- fragment事务回退栈
通常的事务有以下几个:
(1)给Activity添加fragment
FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)
- containerViewId为容器视图的资源Id,容器视图资源ID的作用有:
告诉FragmentManager,fragment视图应该出现在activity视图的什么位置;
唯一标识FragmentManager队列中的fragment。
容器视图的xml文件可服务于一个或多个fragment,用来放置fragment的视图。 - fragment为待放置的fragment
- tag为自定义标签,可用以下方法获取fragment
Fragment findFragmentByTag(String tag)
(2)在Activity中删除一个fragment
FragmentTransaction remove(Fragment fragment)
(3)用一个fragment替换当前fragment
FragmentTransaction replace(int containerViewId, Fragment fragment, String tag)
(4)添加用于管理后台的非UI的fragment
FragmentTransaction add(Fragment fragment, String tag)
为fragment提供一个唯一的字符串标记 tag,而不是视图 ID,如果fragment没有 UI,则字符串标记将是标识它的唯一方式。该方法会添加fragment,但由于它并不与 Activity 布局中的视图关联,因此不会收到对 onCreateView() 的调用。因此不需要实现该方法。
(5)commit()使修改生效
当完成了片段的修改后,需要提交以使修改生效
FragmentTransaction.commit()
9、正确采用fragment的应用架构
- 不能滥用fragment
fragment是用来封装关键组件以方便复用。这里所说的关键组件,是针对应用的整个屏幕来讲的。如果单屏就使用大量fragment,不仅应用代码充斥着fragment事务处理,模块的职责分工也会不清晰。如果有很多零碎小组件要复用,比较好的架构设计是使用定制视图(使用View子类)。
总之,一定要合理使用fragment。实践证明,应用单屏最多使用2~3个fragment。
- 不要纠结用不用fragment,要用的话从项目一开始就用。
有人可能觉得,在应用开发初期暂不使用fragment,等到需要时再添加它会好一些。极限编程方法论中有个YAGNI原则。YAGNI(You Aren’t Gonna Need It)的意思是“你不会需要它”,该原则鼓励大家不要去实现那些有可能需要的东西。为什么呢?因为你不会需要它。因此,YAGNI原则等于在说,可用可不用,那就不要用fragment了。
经验表明,后期添加fragment就如同掉泥坑。从activity管理用户界面调整到由
activity托管UI fragment虽然不难,但会有一大堆恼人的问题等着你。你也可能会想让部分用户界面仍由activity管理,部分用户界面改用fragment管理,这只会让事情更糟。哪些不改,哪些要改,光理清这些就够你头痛的了。显然,从一开始就使用fragment更容易,既不用返工,也不会出现理不清哪个部分使用了哪种视图控制风格这种事了。