Android开发--Fragment

概要

1.Fragment 英文原意是“片断”或“碎片”,在 Android 系统中代表用户界面的局部区域,它可以是一个活动的部分,
    可以单独设置局部用户界面,也可以单独接收用户输入和处理事件消息,与用户交互

2.Android 在 Android 3.0(API 级别 11)中引入了片段,主要目的是为大屏幕(如平板电脑)上
    更加动态和灵活的界面设计提供支持

3.Fragment 的出现是为了适应平板电脑等大屏幕设备,改变了早期因手机屏幕较小而将整个屏幕作为一个整体界面
    处理的状况,Fragment 组件可以将屏幕分成多个相对独立的区域,用户界面的更新可以在>局部区域发生,使得用户
    界面切换方式更加高效、丰富

4.每个片段都会通过各自的生命周期回调来定义自己的布局和行为,您可以将一个片段加入多个 Activity,因此,
    您应采用可复用式设计,避免直接通过某个片段操纵另一个片段

创建片段

如要创建片段,您必须创建 Fragment 的子类(或已有其子类)。Fragment 类的代码与 Activity 非常相似。
它包含与 Activity 类似的回调方法,如 onCreate()、onStart()、onPause() 和 onStop()。实际上,
如果您要将现有 Android 应用转换为使用片段,可能只需将代码从 Activity 的回调方法移入片段相应的回调方法中。

片段通常用作 Activity 界面的一部分,并且会将其自己的布局融入 Activity。
如要为片段提供布局,您必须实现 onCreateView() 回调方法,Android 系统会在片段需要绘制其布局时调用该方法。
此方法的实现所返回的 View 必须是片段布局的根视图。

如要从 onCreateView() 返回布局,您可以通过 XML 中定义的布局资源来扩展布局。为帮助您执行此操作,
onCreateView() 提供了一个 LayoutInflater 对象。

例:
1
2
3
4
5
6
7
8
public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
传递至 onCreateView() 的 container 参数是您的片段布局将插入到的父级 ViewGroup(来自 Activity 的布局)。
savedInstanceState 参数是在恢复片段时,提供上一片段实例相关数据的 Bundle

inflate() 方法带有三个参数:
1.您想要扩展的布局的资源 ID。
2.将作为扩展布局父项的 ViewGroup。传递 container 对系统向扩展布局的根视图(由其所属的父视图指定)
    应用布局参数具有重要意义。
3.指示是否应在扩展期间将扩展布局附加至 ViewGroup(第二个参数)的布尔值。(在本例中,此值为 false,
    因为系统已将扩展布局插入 container,而传递 true 值会在最终布局中创建一个多余的视图组。)

添加片段

通常,片段会向宿主 Activity 贡献一部分界面,作为 Activity 整体视图层次结构的一部分嵌入到 Activity 中。
可以通过两种方式向 Activity 布局添加片段:
1.在 Activity 的布局文件内声明片段
例如,以下是拥有两个片段的 Activity 的布局文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
 中的 android:name 属性指定要在布局中进行实例化的 Fragment 类。创建此 Activity 布局时,
系统会将布局中指定的每个片段实例化,并为每个片段调用 onCreateView() 方法,以检索每个片段的布局。
系统会直接插入片段返回的 View,从而代替  元素。
2.通过编程方式将片段添加到某个现有 ViewGroup
在 Activity 运行期间,您可以随时将片段添加到 Activity 布局中。您只需指定要将片段放入哪个 ViewGroup。
如要在您的 Activity 中执行片段事务(如添加、移除或替换片段),则必须使用 FragmentTransaction 中的 API。
如下所示,您可以从 FragmentActivity 获取一个 FragmentTransaction 实例
1
2
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
然后,您可以使用 add() 方法添加一个片段,指定要添加的片段以及将其插入哪个视图。例如:
1
2
3
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
传递到 add() 的第一个参数是 ViewGroup,即应放置片段的位置,由资源 ID 指定,第二个参数是要添加的片段。
一旦您通过 FragmentTransaction 做出了更改,就必须调用 commit() 以使更改生效。

生命周期

Fragment生命周期图示如下,与Activity有所不同

Fragment.jpg

Activity.jpg
下面来分析生命周期
onAttach()
onAttach()回调将在Fragment与其Activity关联之后调用。
需要使用Activity的引用或者使用Activity作为其他操作的上下文,将在此回调方法中实现
onCreate(Bundle savedInstanceState)
此时的Fragment的onCreat回调时,该fragmet还没有获得Activity的onCreate()已完成的通知,
所以不能将依赖于Activity视图层次结构存在性的代码放入此回调方法中。在onCreate()回调方法中,
我们应该尽量避免耗时操作。此时的bundle就可以获取到activity传来的参数
onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
其中的Bundle为状态包与上面的bundle不一样。
注意的是:不要将视图层次结构附加到传入的ViewGroup父元素中,该关联会自动完成。
如果在此回调中将碎片的视图层次结构附加到父元素,很可能会出现异常。
这句话什么意思呢?就是不要把初始化的view视图主动添加到container里面,
因为这会系统自带,所以inflate函数的第三个参数必须填false,而且不能出现container.addView(v)的操作。
1
View v = inflater.inflate(R.layout.hello_world, container, false);
onActivityCreated()
onActivityCreated()回调会在Activity完成其onCreate()回调之后调用。
在调用onActivityCreated()之前,Activity的视图层次结构已经准备好了,
这是在用户看到用户界面之前你可对用户界面执行的最后调整的地方。

Note:如果Activity和它的Fragment是从保存的状态重新创建的,此回调尤其重要,
也可以在这里确保此Activity的其他所有Fragment已经附加到该Activity中了
onStart()\onResume()\onPause()\onStop()
这四种生命周期和Activity的回调方法进行绑定,也就是说与Activity中对应的生命周期相同,因此不做过多介绍
onDestroyView()
该回调方法在视图层次结构与Fragment分离之后调用
onDestroy()
不再使用Fragment时调用。(备注:Fragment仍然附加到Activity并任然可以找到,但是不能执行其他操作)
onDetach()
Fragme生命周期最后回调函数,调用后,Fragment不再与Activity绑定,释放资源。
setRetainInstance()
在使用Fragment时,我发现了一个金矿,那就是setRetainInstance()方法,此方法可以有效地提高系统的运行效率,
对流畅性要求较高的应用可以适当采用此方法进行设置。Fragment有一个非常强大的功能——就是可以在Activity重新创建时
可以不完全销毁Fragment,以便Fragment可以恢复。在onCreate()方法中调用setRetainInstance(true/false)方法是最佳位置。
当Fragment恢复时的生命周期如上图所示,注意图中的红色箭头。当在onCreate()方法中调用了setRetainInstance(true)后,
Fragment恢复时会跳过onCreate()和onDestroy()方法,因此不能在onCreate()中放置一些初始化逻辑,切忌!