Fragment 的生命周期及使用方法详解

Fragment 的基础知识介绍 1.1 概述 数据库

1.1.1 特性 ide

By hebang32624 模块化

Fragment 是 activity 的界面中的一部分或一种行为。能够把多个 Fragment 组合到一个 activity 中来建立一 个多面界面而且能够在多个 activity 中重用一个 Fragment。能够把 Fragment 认为模块化的一段 activity,它具 有本身的生命周期,接收它本身的事件,并能够在 activity 运行时被添加或删除。 函数

Fragment 不能独立存在,它必须嵌入到 activity 中,并且 Fragment 的生命周期直接受所在的 activity 的影 响。例如:当 activity 暂停时,它拥有的全部的 Fragment 都暂停了,当 activity 销毁时,它拥有的全部 Fragment 都被销毁。然而,当 activity 运行时(在 onResume()以后,onPause()以前),能够单独地操做每一个 Fragment, 好比添加或删除它们。当在执行上述针对 Fragment 的事务时,能够将事务添加到一个栈中,这个栈被 activity 管 理,栈中的每一条都是一个 Fragment 的一次事务。有了这个栈,就能够反向执行 Fragment 的事务,这样就能够在 Fragment 级支持“返回”键(向后导航)。 布局

当向 activity 中添加一个 Fragment 时,它须置于 ViewGroup 控件中,而且需定义 Fragment 本身的界面。可 以在 layoutxml 文件中声明 Fragment,元素为:<fragment>;也能够在代码中建立 Fragment,而后把它加入到 ViewGroup 控件中。然而,Fragment 不必定非要放在 activity 的界面中,它能够隐藏在后台为 actvitiy 工做。 this

1.1.2 生命周期 .net

onCreate():
当建立 fragment 时系统调用此方法。在其中必须初始化 fragment 的基础组件们。可参考 activity 的说明。 onCreateView():
系统在 fragment 要画本身的界面时调用(在真正显示以前)此方法。这个方法必须返回 frament 的 layout 的根控 件。若是这个 fragment 不提供界面,那它应返回 null。
onPause():
大多数程序应最少对 fragment 实现这三个方法。固然还有其它几个回调方法可应该按状况实现之。全部的生命周 期回调函数在“操控 fragment 的生命周期”一节中有详细讨论。 线程

下图为 fragment 的生命周期(它所在的 activity 处于运行状态)。 设计

 
 

添加Fragments code

onAttach()

onCreate()

onCreateView()

onActivityCreated()

onStart()

onResume()

Fragments是活动的(正在使 用)

 
 
 
 
 
 

Fragment从

返回堆栈中 返回到布局文件

 

用户使用返 回功能或 Fragments 被移除 (替换)

 

Fragments被

添加到返回 堆栈中,接着 被移除(替换)

onPause()

 
 
 
 

onStop

 
 
 
 

onDestroyView()

onDestroy()

onDetach()

Fragments被销毁

图 1 Fragment 生命周期

1.1.3 派生类

DialogFragment
显示一个浮动的对话框。使用这个类建立对话框是替代 activity 建立对话框的最佳选择.由于能够把 fragmentdialog 放入到 activity 的返回栈中,使用户能再返回到这个对话框。
ListFragment
显示一个列表控件,就像 ListActivity 类,它提供了不少管理列表的方法,好比 onListItemClick()方法响应 click 事件。 PreferenceFragment
显示一个由 Preference 对象组成的列表,与 PreferenceActivity 相同。它用于为程序建立“设置”activity。

 

1.2 范例

写一个读新闻的程序,能够用一个 fragment 显示标题列表,另外一个 fragment 显示选中标题的内容,这两个 fragment 都在一个 activity 上,并排显示。那么这两个 fragment 都有本身的生命周期并响应本身感兴趣的事件。于 是,不需再像手机上那样用一个 activity 显示标题列表,用另外一个 activity 显示新闻内容;如今能够把二者放在一个 activity 上同时显示出来。以下图:

图 2 Fragment 说明性示例
Fragment 必须被写成可重用的模块。由于 fragment 有本身的 layout,本身进行事件响应,拥有本身的生命周期

和行为,因此能够在多个 activity 中包含同一个 Fragment 的不一样实例。这对于让界面在不一样的屏幕尺寸下都能给用 户完美的体验尤为重要。好比能够在程序运行于大屏幕中时启动包含不少 fragment 的 activity,而在运行于小屏幕 时启动一个包含少许 fragment 的 activity。

刚才读新闻的程序,当检测到程序运行于大屏幕时,启动 activityA,将标题列表和新闻内容这两个 fragment 都 放在 activityA 中;当检测到程序运行于小屏幕时,仍是启动 activityA,但此时 A 中只有标题列表 fragment,当选中 一个标题时,activityA 启动 activityB,B 中含有新闻内容 fragment。

1.3 建立 Fragmet

要建立 fragment,必须从 Fragment 或 Fragment 的派生类派生出一个类。Fragment 的代码写起来有些像 activity。它 具备跟 activity 同样的回调方法,好比 onCreate(),onStart(),onPause()和 onStop()。实际上,若是想把老的程序改成使 用 fragment,基本上只须要把 activity 的回调方法的代码移到 fragment 中对应的方法便可。

1.3.1 添加有界面的 Fragment

Fragment 通常做为 activity 的用户界面的一部分,把它本身的 layout 嵌入到 activity 的 layout 中。一个要为 fragment 提供 layout,必须实现 onCreateView()回调方法,而后在这个方法中返回一个 View 对象,这个对象是 fragment 的 layout 的根。

注意:若是的 fragment 是从 ListFragment 中派生的,就不须要实现 onCreateView()方法了,由于默认的实现已 经为返回了 ListView 控件对象。

要从 onCreateView()方法中返回 layout 对象,能够从 layoutxml 中生成 layout 对象。为了帮助这样作, onCreateView()提供了一个 LayoutInflater 对象。举例:如下代码展现了一个 Fragment 的子类如何从 layoutxml 文件 example_fragment.xml 中生成对象。

PublicstaticclassExamp leFragmentextendsFragment{ @Override

P ublicV iew onCreat e View (L ay out Inflat erinflat er,View G roup cont ainer, BundlesavedInstanceState){

//Inflate the layout for this fragment

 

ret urninflat er.inflat e(R.l ay out .examp le_fra gm ent ,cont ainer,false) ; }

}
onCreateView()参数中的 container 是存放 fragment 的 layout 的 ViewGroup 对象。savedInstanceState

参数是一个Bundle,跟 activity的onCreate()中 Bundle差很少,用于状态恢复。可是 fragment的onCreate() 中也有 Bundle 参数,因此此处的 Bundle 中存放的数据与 onCreate()中存放的数据仍是不一样的。

Inflate()方法有三个参数:
layout 的资源 ID。
存放 fragment 的 layout 的 ViewGroup。
布尔型数据表示是否在建立 fragment 的 layout 期间,把 layout 附加到 container 上(在这个例子

中,由于系统已经把 layout 插入到 container 中了,因此值为 false,若是为 true 会导至在最终的 layout 中建立多余的 ViewGroup)。

下面讲述如何把它添加到 activity 中。把 fragment 添加到 activity 通常状况下,fragment 把它的 layout 做为 activitiy 的 loyout 的一部分合并到 activity 中,有两种方法将一个 fragment 添加到 activity 中:

方法一:在 activity 的 layoutxml 文件中声明 fragment 以下代码,一个 activity 中包含两个 fragment:

<?xmlversion="1.0"encoding="utf-8"?>
<LinearLay outxmlns:Android="http ://schemas.Android.co m/ap k/res/Android"

Android:orientation="horizontal" Android:layout_width="match_parent" Android:layout_height="match_parent">
<fragm ent Android:name="co m.e xa mp le.news.Art icleList Fragment "

Android:id="@+id/list" Android:layout_weight="1" Android:layout_width="0dp"

Android:layout_height="match_parent"/>
<fragm ent Android:name="co m.e xa mp le.news.Art icleReaderFra gment "

Android:id="@+id/viewer" Android:layout_weight="2" Android:layout_width="0dp"

Android:layout_height="match_parent"/> </LinearLayout>

以上代码中,<fragment>中声明一个 fragment。当系统建立上例中的 layout 时,它实例化每个 fragment,然 后调用它们的 onCreateView()方法,以获取每一个 fragment 的 layout。系统把 fragment 返回的 view 对象插入到<fragment> 元素的位置,直接代替<fragment>元素。

注:每一个 fragment 都须要提供一个 ID,系统在 activity 从新建立时用它来恢复 fragment,也能够用它来操做 fragment 进行其它的事物,好比删除它。有三种方法给 fragment 提供 ID:
为 Android:id 属性赋一个数字。
为 Android:tag 属性赋一个字符串。

若是没有使用上述任何一种方法,系统将使用 fragment 的容器的 ID。

方法二:在代码中添加 fragment 到一个 ViewGroup
这种方法能够在运行时,把 fragment 添加到 activity 的 layout 中。只需指定一个要包含 fragment 的 ViewGroup。

为了完成 fragment 的事务(好比添加,删除,替换等),必须使用 FragmentTransaction 的方法。

 

取到 FragmentTransaction,以下:
FragmentManagerfragmentManager =getFragmentManager() FragmentTransactionfragmentTransaction=fragmentManager.beginTransaction();

而后能够用 add()方法添加一个 fragment,它有参数用于指定容纳 fragment 的 ViewGroup。如,Add()的第一个 参数是容器 ViewGroup,第二个是要添加的 fragment。一旦经过 FragmentTransaction 对 fragment 作出了改变,必须 调用方法 commit()提交这些改变。不只在无界面的 fragment 中,在有界面的 fragment 中也可使用 tag 来做为为一 标志,这样在须要获取 fragment 对象时,要调用 findFragmentTag()。

1.3.2 添加没有界面的 Fragment

上面演示了如何添加 fragment 来提供界面,然而,也可使用 fragment 为 activity 提供后台的行为而不用显示 fragment 的界面。要添加一个没有界面的 fragment,需在 activity 中调用方法 add(Fragment,String)(它支持用一个惟 一的字符串作为 fragment 的“tag”,而不是 viewID)。这样添加的 fragment 因为没有界面,因此在实现它时不需 调用实现 onCreateView()方法。

使用 tag 字符串来标识一个 fragment 并非只能用于没有界面的 fragment 上,也能够把它用于有界面的 fragment 上,可是,若是一个 fragment 没有界面,tag 字符串将成为它惟一的选择。获取以 tag 标识的 fragment,需使用方法 findFragmentByTab()。

1.4 Frament 管理

要管理 fragment,需使用 FragmentManager,要获取它,需在 activity 中调用方法 getFragmentManager()。 能够用 FragmentManager 来作以上事情:
使用方法 findFragmentById()或 findFragmentByTag(),获取 activity 中已存在的 fragment
使用方法 popBackStack()从 activity 的后退栈中弹出 fragment(这能够模拟后退键引起的动做)

用方法 addOnBackStackChangedListerner()注册一个侦听器以监视后退栈的变化
还可使用 FragmentManager 打开一个 FragmentTransaction 来执行 fragment 的事务,好比添加或删除 fragment。

在 activity 中使用 fragment 的一个伟大的好处是能跟据用户的输入对 fragment 进行添加、删除、替换以及执行 其它动做的能力。提交的一组 fragment 的变化叫作一个事务。事务经过 FragmentTransaction 来执行。还能够把每一个 事务保存在 activity 的后退栈中,这样就可让用户在 fragment 变化之间导航(跟在 activity 之间导航同样)。

能够经过 FragmentManager 来取得 FragmentTransaction 的实例,以下:
FragmentManagerfragmentManager = getFragmentManager();
FragmentTransactionfragmentTransaction =fragmentManager.beginTransaction(); 一个事务是在同一时刻执行的一组动做(很像数据库中的事务)。能够用 add(),remove(),replace()等方法构成事

务,最后使用 commit()方法提交事务。在调用 commint()以前,能够用 addToBackStack()把事务添加到一个后退栈中, 这个后退栈属于所在的 activity。有了它,就能够在用户按下返回键时,返回到 fragment 执行事务以前的状态。如 下例:演示了如何用一个 fragment 代替另外一个 fragment,同时在后退栈中保存被代替的 fragment 的状态。

//Create new fragment and transaction
Fragment newFragment = newExampleFragment();
FragmentTransaction transaction=getFragmentManager().beginTransaction();

//Replace whatever is in the fragment_container view with thisfragment, //and add the transaction to the backstack
t ransact ion.rep lace(R.id.fra gm ent _cont ainer,new Fra gment );

transaction.addToBackStack(null) ;

//Commit the transaction transaction.commit();

解释:newFragment 代替了控件 IDR.id.fragment_container 所指向的 ViewGroup 中所含的任何 fragment。而后调 用 addToBackStack(),此时被代替的 fragment 就被放入后退栈中,因而当用户按下返回键时,事务发生回溯,原先 的 fragment 又回来了。

若是向事务添加了多个动做,好比屡次调用了 add(),remove()等以后又调用了 addToBackStack()方法,那么全部 的在 commit()以前调用的方法都被做为一个事务。当用户按返回键时,全部的动做都被反向执行(事务回溯)。

事务中动做的执行顺序可随意,但要注意如下两点:
必须最后调用 commit()
若是添加了多个 fragment,那么它们的显示顺序跟添加顺序一至(后显示的覆盖前面的) 若是在执行的事务中有删除 fragment 的动做,并且没有调用 addToBackStack(),那么当事务提交时,那些被删

除的 fragment 就被销毁了。反之,那些 fragment 就不会被销毁,而是处于中止状态。当用户返回时,它们会被恢复。 可是,调用 commit()后,事务并不会立刻执行。它会在 activity 的 UI 线程(其实就是主线程)中等待直到线程 能执行的时候才执行(废话)。若是必要,能够在 UI 线程中调用 executePendingTransactions()方法来当即执行事务。

但通常不需这样作,除非有其它线程在等待事务的执行。

注意:只能在 activity 处于可保存状态的状态时,好比 running 中,onPause()方法和 onStop()方法中提交事务, 不然会引起异常。这是由于 fragment 的状态会丢失。若是要在可能丢失状态的状况下提交事务,请使用 commitAllowingStateLoss()。

1.5 Fragment 与 Activity 通信

尽管 fragment 的实现是独立于 activity 的,能够被用于多个 activity,可是每一个 activity 所包含的是同一个 fragment 的不一样的实例。Fragment 能够调用 getActivity()方法很容易的获得它所在的 activity 的对象,而后就能够查找 activity 中的控件们(findViewById())。例如:
ViewlistView =getActivity().findViewById(R.id.list);一样的,activity 也能够经过 FragmentManager 的方 法查找它所包含的 frament 们。

例如:

Examp leFra gment
fragment =(ExampleFragment)getFragmentManager().findFragmentById(R.id.example_fragment )

有时,可能须要 fragment 与 activity 共享事件。一个好办法是在 fragment 中定义一个回调接口,而后在 activity 中实现之。例如,仍是那个新闻程序的例子,它有一个 activity,activity 中含有两个 fragment。fragmentA 显示新闻标题,fragmentB 显示标题对应的内容。fragmentA 必须在用户选择了某个标题时告诉 activity,而后 activity 再告诉 fragmentB,fragmentB 就显示出对应的内容。

以下例,OnArticleSelectedListener 接口在 fragmentA 中定义:

public static class FragmentA extends ListFragment{ //Container Activity must implement this interface

public interface OnArticleSelectedListener{
public void onArticleSelected(Uri articleUri);

}

而后 activity 实现接口 OnArticleSelectedListener,在方法 onArticleSelected()中通知 fragmentB。当 fragment 添加到 activity 中时,会调用 fragment 的方法 onAttach(),这个方法中适合检查 activity 是否实现了

 

OnArticleSelectedListener 接口,检查方法就是对传入的 activity 的实例进行类型转换,以下所示:

public static class FragmentA extends ListFragment{ OnArticleSelectedListenermListener;
...
@Override

public void onAttach(Activity activity){ super.onAttach(activity);
try{

mListener =(OnArticleSelectedListener)activity; }catch(ClassCastException e){

throw new ClassCastException(activity.toString()+"must implement OnArticleSelectedListener"); }

}

若是 activity 没有实现那个接口,fragment 抛出 ClassCastException 异常。若是成功了,mListener 成员变 量保存 OnArticleSelectedListener 的实例。因而 fragmentA 就能够调用 mListener 的方法来与 activity 共享事 件。例如,若是 fragmentA 是一个 ListFragment,每次选中列表的一项时,就会调用 fragmentA 的 onListItemClick() 方法,在这个方法中调用 onArticleSelected()来与 activity 共享事件,以下:
public static class FragmentA extends ListFragment{

OnArticleSelectedListenermListener;
...
@Override
public void onListItemClick(ListViewl,Viewv,intposition,long id){

//Append the clicked item's row ID with the content provider Uri
Uri noteUri =ContentUris.withAppendedId(ArticleColumns.CONTENT_URI,id); //Send the event and Uri to the host activity mListener.onArticleSelected(noteUri);

}
onListItemClick()传入的参数 id 是列表的被选中的行 ID,另外一个 fragment 用这个 ID 来从程序的

ContentProvider 中取得标题的内容。

http://www.yidin.net/?p=9679

更多的移动互联网的发展趋势拓者设计吧效果图移动互联网应用相关的资料请到互联网的一点事www.yidin.net 留言

相关文章
相关标签/搜索