Fragment,俗称碎片,自Android 3.0开始被引进并大量使用。然而就是这样耳熟能详的一个东西,在开发中我们还是会遇见各种各样的问题,层出不穷。所以,是时候总结一波了。
简介
作为 Activity界面的一部分,Fragment的存在必须依附于 Activity,并且与Activity一样,拥有自己的生命周期,同时处理用户的交互动作。同一个Activity 可以有一个或多个Fragment作为界面内容,并且可以动态添加、删除Fragment,灵活控制 UI内容,也可以用来解决部分屏幕适配问题。
另外,support v4包中也提供了Fragment,兼容 Android 3.0之前的系统(当然,现在3.0之前的系统在市场上已经很少见了,可以不予考虑),使用兼容包需要注意两点:
Activity 必须继承自 FragmentActivity;
使用 getSupportFragmentManager()方法获取FragmentManager对象;
创建实例
像普通的类一样,Fragment拥有自己的构造函数,于是我们可以像下面这样在Activity中创建 Fragment实例:
Fragment fragment=new Fragment();
如果需要在创建 Fragment实例时传递参数进行初始化的话,可以创建一个带参数的构造函数,并初始化Fragment 成员变量等。这样做,看似没有问题,但在一些特殊状况下还是有问题的。
我们知道,Activity在一些特殊状况下会发生destroy并重新 create的情形,比如屏幕旋转、内存吃紧时;对应的,依附于Activity存在的Fragment 也会发生类似的状况。而一旦重新create时,Fragment便会调用默认的无参构造函数,导致无法执行有参构造函数进行初始化工作。
嵌入方式
1、静态嵌入
Activity 嵌入 Fragment 分为布局静态嵌入和代码动态嵌入两种。前者在Activity的Layout 布局中使用 <fragment> 标签嵌入指定Fragment,如:
- ?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <fragment
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- class="com.yifeng.samples.OneFragment"/>
- </LinearLayout>
?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.yifeng.samples.OneFragment"/>
</LinearLayout>
2、动态嵌入
在 Activity的Java代码中借助管理器类FragmentManager 和 事务类FragmentTransaction提供的replace()等方法替换 Activity的Layout中的相应容器布局,如:
- FragmentManager fm = getFragmentManager();
- FragmentTransaction ft = fm.beginTransaction();
- ft.replace(R.id.fl_content, OneFragment.newInstance());
- ft.commit();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fl_content, OneFragment.newInstance());
ft.commit();
这两种嵌入方式对应的 Fragment生命周期略有不同,从生命周期图中可以看出。相比布局静态嵌入方式,代码动态嵌入方式更为常用,毕竟后者能够实现灵活控制多个Fragment ,动态改变Activity中的内容。
getChildFragmentManager()
像上面这样,在 Activity嵌入Fragment时,需要使用 FragmentManager,通过Activity提供的getFragmentManager() 方法即可获取,用于管理Activity里面嵌入的所有一级Fragment。
然而有时候,我们会在 Fragment里面继续嵌套二级甚至三级Fragment,即 Activity嵌套多级Fragment。此时在Fragment 里管理子Fragment时,也需要使用到FragmentManager。但是一定要使用 getChildFragmentManager()方法获取FragmentManager对象!
FragmentTransaction
Fragment 的动态添加、删除等操作都需要借助于 FragmentTransaction类来完成,比如上面提到的replace() 操作。FragmentTransaction提供有很多方法供开发人员操作Activity里面的 Fragment,具体可以参考官网介绍:FragmentTransaction Public methods,这里介绍几个常用的关键方法:
add() 系列:添加 Fragment到Activity界面中;
remove():移除 Activity中的指定Fragment ;
replace() 系列:通过内部调用 remove()和add() 完成Fragment的修改;
hide() 和 show():隐藏和显示Activity中的 Fragment;
addToBackStack():添加当前事务到回退栈中,即当按下返回键时,界面回归到当前事物状态;
commit():提交事务,所有通过上述方法对 Fragment的改动都必须通过调用commit() 方法完成提交;
注意:动态切换显示 Activity 中的多个 Fragment 时,可以通过replace()实现,也可以hide()和show()方法实现。事实上,我们更倾向于使用后者,因为 replace()方法不会保留Fragment的状态,也就是说诸如EditText内容输入等用户操作在remove()时会消失。当然,如果你不想保留用户操作的话,可以选择前者,视情况而定。
生命周期
生命周期总结
1、Activity在onCreate与onStart 之间,fragment依次执行onAttach、 onCreate、onCreateView、onActivityCreated ;
2、Activity与Fragment处于活跃状态前,Activity 方法在Fragment对应方法之前执行;
3、在双方活跃状态之后,Fragment对应方法在Activity之前执行;
4、Fragemnt在onAttach方法中就已经可以getActivity ;
5、双方的onSaveInstanceState可能在各自的onPause方法之后, onDestroy之前的任何时刻执行;
6、Fragment的构造方法一定在onAttach之前执行:若Fragment 是Activity的成员变量,声明即创建实例,Fragment构造会先于 Activity构造前执行;
7、Activity的onActivityResult方法在onStart 与onResume之间执行;
8、Fragment没有onRestart方法。
Fragment切换
1、add/show/hide
总结:
两个fragment只在add 时执行生命周期方法,show和hide时不走任何生命周期方法,但会执行 onHiddenChanged方法;
A从onAttach执行到onActivityCreated 之后B重复像A的顺序,之后 onStart与onResume交替执行
2、add/attach/detach
detach B、attach A:
如果A之前没有destroy, A此时不走任何生命周期方法,而B会依次onPause 、onStop、onDestry;
如果A之前销毁了,B先依次 onPause、onStop、onDestry ,然后A依次onCreateView、 onViewCreated、onActivityCreated、onStart 、onResume
都不会重走onAttach和onDetach
3、replace //不需要先add
A replace B:
A依次执行onPause、onStop 、onDestroyView、onDestroy、 onDetach,之后B开始依次onAttach 、onCreate、onCreateView、 onActivityCreated、onStart、onResume
生命周期在replace时全部重走,其内部通过add 与remove实现。