Fragments
来源:互联网 发布:北京 软件 培训 编辑:程序博客网 时间:2024/05/22 14:36
(一)Fragments要点:
a) Fragment表现为一个Activity用户界面的一部分;
b) 你可以合并多个fragment在一个单独的activity中;
c) 也可以在多个activity中重复使用一个Fragment;
d) Fragment有自己的生命周期;
e) 接收自己的输入事件;
f) 在activity运行的过程中,你可以添加或移除一个Fragment;
g) 一个Fragment必须嵌入在一个Activity中使用,Fragment的生命周期由其宿主Activity控制
例如:一个Activity A,含有两个Fragment(F1、F2),当A进入pause()时,F1、F2也都会进入pause()状态;而当A进入destroy状态时,F1、F2也都会进入destroy状态。 但是,当A正在运行时(处于resume状态),可以单独的管理每一个Fragment(F1、F2),比如添加F1或者删除F2。
h) Activity在管理Fragment时是通过FragmentManager和FragmentTransaction进行的,对Fragment的add()、remove()和replace()的操作都需要在一个Transaction中管理;
i) 当对Fragment进行操作时,可以把这些操作放在一个由Activity维护的后台堆栈中(Stack),Stack中的每一个元素都是对Fragment进行操作的事务记录;当用户按下回退键(Back)时,可以从Stack中回溯一个事务;
j) Fragment可以作为布局(Layout)的一部分添加到Activity中,也可以作为一个没有视图界面的单纯的工作器(Worker)添加到Activity中。
当fragment作为Layout添加时,Fragment就相当于Activity的总体视图系统的一部分,它应当被添加到某一个ViewGroup中。可以使用<fragment>标签在Activity的layout文件中添加,也可以用编码方式添加
(二)设计哲学
在3.0中引入的Fragment的概念,主要是为了能够在大尺寸的屏幕上(如Tablet)支持更加灵活的UI设计。在大尺寸屏幕上有更多的空间可以放置更多的视图控件,这也意味着应用程序可能要处理更多的用户交互。
没有Fragment的概念之前,Activity会负责整个的布局管理,如果用户交互逻辑很多,Activity就会非常臃肿且难以维护。而Fragment的主要作用就是帮Activity分担这些布局管理工作,把对布局、视图的操作和一些业务逻辑分拆到多个Fragment中。 总之,Activity(Controller)和Layout(View)之间加入Fragment的概念的好处,首先是将Acitivty对用户交互的逻辑模块化,其次是可以非常灵活的重用这些Fragment。
例如上图,左侧是一个邮件列表,右侧是一个邮件内容查看界面。
1.以前,在手机或者Tablet屏幕上,会将列表布局(LayoutA)放在一个ActivityA中处理,但用户点击一封邮件条目时,屏幕会跳转到另一个邮件内容查看界面(LayoutB),而LayoutB是放在一个ActivityB中处理的;
2.现在,在Tablet屏幕上,有了Fragment的概念以后,我们可以将LayoutA放在一个FragmentA中处理,将LayoutB放在FragmentB中处理,同时将FragmentA和FragmentB统一交给ActivityA维护,就不需要ActivityB了;
3. Fragment的概念并不是只适用于大尺寸屏幕,它也可以自适应到小尺寸的屏幕上。比如使用了Fragment的概念针对Tablet 编写了一套邮件客户端,后来又希望将这个客户端放到一个手机上运行,此时不需要更改布局代码,应用本身会自动的将FragmentA和FragmentB分开显示,既先显示邮件列表界面,当选中某封邮件时会跳转到另一个界面显示邮件详细内容
(三)创建Fragment
创建Fragment和创建Activity类似,只需要继承Fragment类(或其子类)并实现一些必要的生命周期回调方法。 应当实现的生命周期方法有:
onAttach() 在fragment关联到activity被调用一次
onCreate() 当Fragment被创建时会被调用;
onCreateView() 第一次绘制界面时会被调用,有界面的Fragment,返回它的Layout的根视图;没有界面的,返回null;
onActivityCreate()告诉fragment宿主activity已经完成了自身的Activity.onCreate()
onViewStateRestored()告知fragment所有的view布局状态已经被存储
onStart() 使得fragment对于用户是visible的
onResume() 使得fragment对于用户是可以交互的
onPause()fragment不在和用户交互了,原因是对fragment做了操作或者所在activity被paused
onStop() fragment不可见了。原因原因是对fragment做了操作或者所在activity被stoped
onDestroyView()让fragment清除关联View的资源
onDestroy()destory fragment
onDetach() 立即断开和宿主activity的关联关系
1,添加用户交互接口
一般情况下fragment都会提供一个layout,这就需要实现onCreateView()方法。例如:
- 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);
- }
- }
参数container 就是fragment所在layout。
inflate方法第三个参数false是因为这个fragment已经在container的layout中的了。如果为true就会在layout中生成冗余的view。
2. 添加Fragment到Activity中
如之前所说的,有两种方法将Fragment添加到Activity中。
1.1.在Activity 的layout文件中添加Fragment使用这种方式,可以把Fragment理解为一个普通的View,可以制定它的布局属性,
- <?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>
注意<fragment>“标签的android:name”属性的值是你自定义的Fragment类的全路径名。
当系统创建Activity的布局时,会初始化每一个Fragment,调用它们的onCreateView(...)方法获取Layout,并用Layout替换掉相应的<fragment>标签。
完全当做view来看待,可以通过show,hide的逻辑来操作一个layout下的多层fragment,这个适用于简单的逻辑。
注意:每一个Fragment都需要有一个唯一的标识符(ID),如果Activity进入restart状态,系统可以根据这个ID 重新载入对应的Fragment;另外,你也可以用这个ID 对相应的Fragment做一些事务性操作,如remove()。有三种方式可以为一个Fragment设 置ID:
a,在<fragment>“标签中设置android:id”属性,提供一个唯一的ID;
b,在<fragment>“标签中设置android:tag”属性,提供一个唯一的字符串;
c,如果以上两种属性都没有设置,系统会使用这个Fragment的父容器的ID。
1.2.用编码的方式添加Fragment到一个已存在ViewGroup中
在activity运行的任何时刻,都可以将一个Fragment添加到Activity的Layout中,只需要简单的提供一个ViewGroup来放置这个Fragment即可。
具体要对Fragment进行操作时,需要在Activity中使用FragmentTransaction,以事务的方式对Fragment进行add、remove和replace。
用以下的方式可以从Activity中获取一个FragmentTransaction实例:
- FragmentManager fragmentManager =getFragmentManager();
- FragmentTransaction fragmentTransaction =fragmentManager.beginTransaction();
- ExampleFragment fragment = new ExampleFragment();
- fragmentTransaction.add(R.id.fragment_container,fragment);
- fragmentTransaction.commit();
3. 添加一个无UI的Fragment可以使用add(Fragment, String)方法向Activity添加一个Fragment实例。
第一个参数是要添加的Fragment实例,因为是无UI的(即这个Fragment实例不会和Activity的Layout中的任何一个View有关联),所以系统不会去调用这个Fragment实例的onCreateView(...)方法,我们也不需要去实现这个方法。第二个参数是该Fragment实例的唯一标识符(不是一个资源ID),同时也是能够标识该实例的唯一途径(无法为其设置资源ID)。例如希望在Activity运行过程中获得该Fragment的引用,可以使用findFragmentByTag(String tag)方法。
无UI的Fragment的代码示例:FragmentRetainInstance.java
(四)管理Fragment
要在Activity中管理Fragment,需要使用FragmentManager,通过调用Activity的方法getFragmentManager()获得FramentManager的对象。你可以使用FragmentManager做这样一些事情:
1.1.获取在Activity中存在的某个Fragment:getFragmentById(int id) – 有UI的Fragment
getFragmentByTag(String tag) – 有UI或无UI的Fragment都可以
1.2.从后台的BackStack中弹出存放的Fragment:popBackStack(...)
1.3.为后台的BackStack添加监听器,监听其任何改动:addOnBackStackChangedListener(...)
1.4.像之前提到过的,可以使用FragmentManager打开一个事务:FragmentTransaction beginTransaction();
(五)执行Fragment事务
使用Fragment的一个非常好的特性,是为了能够和用户交互,可以灵活的add、remove、replace(或其他操作)一个Fragment。你向Activity提交的任何对Fragment的修改都被作为一个事务(Transaction)。可以将每一个Transaction都保存在一个BackStack中(由Activity维护),这样用户就可以使用BACK键回退之前每一次对Fragment的修改了,就像是从一个Activity回退到以前的一个Activity一样。
每一个事务都是同时要执行的一套变化.可以在一个给定的事务中设置你想执行的所有变化,使用诸如 add()、remove()和 replace().然后, 要给activity应用事务, 必须调用 commit().
在调用commit()之前, 你可能想调用 addToBackStack(),将事务添加到一个fragment事务的backstack. 这个back stack由activity管理, 并允许用户通过按下 BACK按键返回到前一个fragment状态.
举个例子, 这里是如何将一个fragment替换为另一个, 并在后台堆栈中保留之前的状态:
- // Create new fragment and transaction
- Fragment newFragment = newExampleFragment();
- FragmentTransaction transaction =getFragmentManager().beginTransaction();
- // Replace whatever is in thefragment_container view with this fragment,
- // and add the transaction to the backstack
- transaction.replace(R.id.fragment_container,newFragment);
- transaction.addToBackStack(null);
- // Commit the transaction
- transaction.commit();
一次更改的所有的操作都包含在一个FragmentTransaction实例中;
BackStack中存放的是FragmentTransaction实例;
commit()操作必须在整个事务的最后执行,其他操作的顺序没有要求(addToBackStack()的调用顺序在文档中没有特别说明,可以认为是只要在commit()之前即可)。
addToBackStack()的作用:假设在一个FragmentTransaction中remove了一个Fragment,如果没有调用addToBackStack(),那么系统会destroy掉这个Fragment,如果调用了addToBackStack(),系统仅仅会stop这个Fragment而不会destroy掉,当用户回退的remove操作的时候,系统会resume这个Fragment。
提示:对于每一个FragmentTransaction,都可以应用一个转换动画(transition animation),使用方法是在commit()之前调用setTransition()方法。
事务在commit()之后,并不会立即执行,而是会被安排在UI线程中尽可能快的执行(应该放在了MessageQueue中)。如果确实有必要,例如在另一个线程中的一项任务要依赖于UI线程中的一个事务执行完毕,那么可以在UI线程中调用executePendingTransactions()去立即执行该事务,除此之外通常没有必要这样做
注意:你只能在一个Activity保存它的状态(onPause、onStop)之前执行commit(),否则的话将会抛出异常,这是因为如果这个Activity需要restore的话,那commit()之后的状态会丢失(不明白,再调查)。如果某些情况下允许丢失commit,可以调用commitAllowingStateLoss()
(六)与Activity通信
尽管Fragment是独立于Activity的,并且可以被多个Activity使用,但是一个给定的Fragment实例是直接与包含它的Activity绑定的。在Fragment中可以使用getActivity()方法访问其宿主Activity,例如:
- View listView =getActivity().findViewById(R.id.list);
- ExampleFragment fragment =(ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
1. 向Activity创建事件回调
有时我们希望能够将在Fragment中获得到的事件共享到Activity中,一种非常好的方式是在Fragment中定义一个回调接口,同时需要宿主Activity实现这个接口。这样,当宿主Activity中接口中获得回调事件时,就可以将事件信息共享到它维护的其他的Fragment中。
举例说明,一个邮件应用,有两个Fragment:
ActivityA – 邮件主界面
FragmentA – 邮件列表界面
FragmentB – 邮件详细信息界面
当用户点击FragmentA列表中的一个邮件条目时,FragmentA应该把这个点击事件传递给ActivityA,这样ActivityA就可以通知FragmentB去显示相应的邮件内容。以下的代码示例中,FragmentA中定义了onArticleSelectedListener接口:
- public static class FragmentA extends ListFragment {
- ...
- // Container Activity must implement this interface
- public interface OnArticleSelectedListener {
- public void onArticleSelected(Uri articleUri);
- }
- ...
- }
- public static class FragmentA extends ListFragment {
- OnArticleSelectedListener mListener;
- ...
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- mListener = (OnArticleSelectedListener) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implementOnArticleSelectedListener");
- }
- }
- ...
- public static class FragmentA extends ListFragment {
- OnArticleSelectedListener mListener;
- ...
- @Override
- public void onListItemClick(ListView l, View v, int position, 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);
- }
- ...
- }
2. 向ActionBar中添加项目
Fragment可以向其宿主Activity的选项菜单(Options Menu)中添加项目(因此也可以向ActionBar中),方法:•在Fragment中重写onCreateOptionsMenu()方法;•在onCreate()方法中调用setHasOptionsMenu(),否则系统不会调用Fragment的onCreateOptionsMenu()方法;Fragment也可以使用registerForContextMenu()来注册一个上下文菜单(Context Menu),当用户要打开一个Context Menu时,会调用onCreateContextMenu(),当用户选择一个条目时,会调用onContextItemSelected()。
注意:尽管Fragment会接收到用户选择菜单选项的事件,但这个事件首先会被Activity获取,如果Activity没有处理这个事件的话,才会把它传给Fragment。
这个规则适用于选项菜单和环境菜单.
(七)处理Fragment的生命周期
Fragment的生命周期和Activity很像,它可以存在于三种状态下:Resumed、Paused、Stopped。
像Activity一样,Fragment也可以使用Bundle,当Activity进程被kill掉的时候,为了能够在Activity被重新创建时恢复Fragment之前的状态,就需要使用onSaveInstanceState()保存Fragment被kill之前的状态,当Fragment被重新创建时,之前保存数据的Bundle就会被传递到Fragment的onCreate()、onCreateView()、和onActivityCreated()方法中。
Fragment的生命周期和Activity相比,最大的区别在于他们是如何被保存在后台堆栈中的。Activity是被stop时,默认的被保存在Task中,Task是一个Activity的堆栈,由系统维护;而Fragment是在被remove时,需要显示指定addToBackStack(),才会被压入由Activity维护的一个事务堆栈。此外,管理Fragment的生命周期与Activity是非常相似的。还需要掌握的一个知识点是Activity的生命周期是如何影响Fragment的生命周期的。如右图:
1. 协调与Activity的生命周期
Activity的生命周期直接影响了它所包含的Fragment的生命周期,当Activity进入到某一种状态时会调用Fragment中相应的状态的方法(如右图所示)。
Fragment还有一些额外的状态方法:onAttach() – 当Fragment被关联到Activity中时;
onCreateView() – 当创建与Fragment关联的视图结构时;
onActivityCreated() – 当activity的onCreate()方法返回时;
onDestroyView() – 当移除与Fragment关联的视图结构时;
onDetach() – 当从Activity中移除Fragment时;
一旦Activity进入resumed状态后,你就可以自由的添加或移除Fragment了。但是当Activity离开resumed状态后,Fragment又会被Activity的生命周期所影响
对于低版本:
Fragment是Android 3.0中引入的新功能,它的引入对于在平板电脑运行的应用很重要。尽管Android已经推出了4.2,可是在市场上仍然有相当数量的设备运行在Android3.0以下的版本,包括一些平板电脑。为了能让低版本的Android设备使用Fragment功能,Google推出了Android支持包。在引入了这个包之后,即使是基于Android 1.6 SDK的应用也可以使用Fragment,把屏幕分成多个部分。
使用Android支持包并且尝试用Fragment代替Activity作为UI的基本构件有两个方面的好处:首先它可以统一Pad应用和手机应用的代码;其次,在引入了支持包之后,基于不同版本SDK的应用可以统一代码。这么做提高了代码的一致性,也降低了应用维护和升级的工作量。
支持包包括多个支持库,每个都有不同的最低API等级,等级包括v4、v7、v13。例如,v4表示此支持包需要的最低Android API的等级是4,也就是Android1.6。v7则是v4的超集,包含v4的全部功能,它需要的最低API等级是7(Android 2.1)。
总结一下,
Fragment是一个“子Activity”或”面板“
能向用户显示数据和功能,与Activity相似
有它关联的视图结构,有生命周期,有返回栈
和Activity紧密联系在一起,包含在Activity中
创建Fragment
继承Fragment类实现生命周期方法,并组合到Activity
为管理Activity中的Fragment会用到FragmentManager与Fragment交互
Fragment操作
在保存状态和还原状态上与Activity 不同,操作简单
创建一个Fragment事物来执行添加,删除等操作
- Fragments
- Fragments
- fragments
- Fragments
- Fragments
- Fragments
- Fragments
- Fragments
- fragments
- Fragments
- Fragments
- Fragments
- Fragments
- Fragments
- Fragments
- Fragments
- fragments
- OSGi Fragments
- mongodb增删改查
- Oracle之约束
- 柳叶湖石锅鱼肉对于成长期的人来说有着增强记忆力
- hdu 1553 Going Home (最大权匹配/费用流)
- 安装ubuntu-12.04+gearbox-9.11+player-3.0.2
- Fragments
- js中 返回上一页和刷新
- JQuery Ajax 在asp.net中使用总结
- const int *p,const * int p,int const *p 面试题考试问题
- 利用Linux syslog写日记
- android数据库操作优化(二)
- java assertion详解
- 第二节 控制台应用程序的基本结构,变量
- HANDLE hToken电脑关机代码