如转载请注明出处http://blog.csdn.net/ethanchiu/article/details/18554887
1.Fragments
一个fragment代表了一个行为或者是activi中ui的一部分。你可以组合多个fragment在一个activity中,并且重复使用一个fragment在多个activity中。你可以把fragment想象成actvity的一个拥有自己生命周期,接受自己事件,并且可以在activity中添加删除的模块。一个fragment必须植入一个activity中,并且activity的生命周期直接影响fragment的生命周期。例如,当activity paused,那么它所有的fragments也会paused,destroyed了一样。然而,当activity正在运行(在resumed状态),你可以独自操作每一个fragment,比如增加或移除。当你执行一个fragment的事务,你也可以把它添加到一个activity管理的后台栈,每一个activity的后台栈入口是fragment事务发生时的记录。后台栈允许用户取消fragment事务(向后导航),通过点back按钮。
当你添加一个fragment座位activity布局的一部分,它贮存在ViewGroup中。可以通过 <fragment> 标记元素把一个fragment插入到activity的布局中,或者从程序代码中添加到存在的ViewGroup。然而,一个fragment不一定作为activity的一部分,你也可以使用一个没有ui的影藏fragment为activity工作。
此文档描述了如何使用fragments创建你的程序,包括添加到activiyt的后台栈后fragment如何管理他们自己的状态,如何分配事件给activity及其里面的fragments,如何给activity的actionbar等提供帮助。
2.设计哲学
3.创建一个Fragment
去创建一个fragment,你必须创建一个Fragment(或者它一个已经存在的子类)。Fragment中的代码里看起来想一个Activity。它包括的回调方法类似activiyt的,比如onCreate(),onStart(),onPause(),和onStop()。事实上,如果你正在使用fragment去转换一个已经存在的android程序,你可以简单地从activiyt的回调方法移动到fragment对应的回调方法。通常,你至少实现以下生命周期方法:
onCreate()
当创建fragment时, 系统调用此方法。在实现代码中,你应该初始化一些必要的组件,所谓必要就是当你fragment paused或者stopped后resumed,这些组件还能保存。
onCreateView()
当Fragment第一次画自己的UI的时候被调用。为了给Fragment画一个UI,你必须在这个方法中返回一个view,这个view是你的Fragment的顶层布局。如果不想要UI可以返回null。
onPause()
用户将要离开fragment时,系统调用这个方法作为第一个指示(然而它不总是意味着fragment将被销毁.) 在当前用户会话结束之前,通常应当在这里提交任何应该持久化的变化(因为用户有可能不会返回).
大多数应用应当为每一个fragment实现至少这3个方法, 但是还有一些其他回调方法你也应当用来去处理fragment生命周期的各种阶段.全部的生命周期回调方法将会在后面章节 Handling the Fragment Lifecycle 中讨论.
添加一个用户界面
一个Fragment常被用作Activity UI的一部分,并将自己的布局提供给Activity。给Fragment提供布局,必须实现onCreateView()回调方法,这个方法在Fragment需要画自己布局的时候会调用。这个方步必须返回一个view作为Fragment的根布局。注意: 如果你的fragment是ListFragment的子类, 它的默认实现是返回从onCreateView()返回一个ListView, 所以一般情况下不必实现它.
为了从onCreateView()返回一个布局,你可以从xml layout资源文件中填充它。为了方便,此方法提供一个LayoutInflater对象。
比如,这里有一个Fragment的子类, 从文件 example_fragment.xml 加载了一个layout :
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);
}
}
添加一个Fragment到Activity中
通常,一个Fragment作为宿主Activity UI中的一部分。有两种方式添加Fragment到Activity layout中。
申明fragment到Activity的layout文件中
在这个例子中,当它作为一个view,你可以在Fragment中使用layout属性。比如,这里是一个拥有两个Fragments的Activity layout文件
<?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类在layout中实例化。当系统创建这个Activity的layout的时候,它会实例化layout中每一个Fragment并且调用onCreateView()方法,来找回每一个Fragment的layout。系统通过元素标签 <fragment> 中的Fragment直接返回View。注意:每一个Fragment需要一个唯一的标记,如果Activity重新开始之后,系统可以恢复Fragment(你可以获得Fragment去执行事务,比如移除它)。有三种方法提供ID。
提供拥有唯一id的android:id 属性。
提供拥有唯一string的android:tag属性。
如果以上两个都不提供,系统使用容器view的ID。
通过编码添加Fragment到已经存在的ViewGroup中
如果Activity在运行,那么任何时候你可以添加Fragment到Activity layout中。你仅仅需要把Fragment添加到指定的一个ViewGroup中。为了用到Fragment的事务(如,添加,删除,替代Fragment),你必须使用FragmentTransaction的API。你可以从Activity中获得一个FragmentTransaction的实例。
像这样:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTrans
你可以通过add()添加一个Fragment,指定添加这个Fragment到一个view中。比如:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
第一个传到add()的参数是一个用于放置Fragment的ViewGroup,ViewGroup通过资源Id指定,第二个参数是Fragment。一旦你已经通过FragmentTransaction改变了设置,你必须调用commit(),这样改变才起效果。
添加一个没有UI的Fragment
以上例子展示了如何通过添加一个Fragment来为Activity提供一个UI。然而,你也可以使用一个Fragment提供一个后台功能,而不是展示一个额外UI。
去添加一个没有UI的Fragment,通过使用add(Fragment, String)添加一个Fragment(提供一个唯一的字符串”tag”,而不是一个view的id)。这个添加的Fragment,由于它和Activity的layout无关,它不会调用onCreateView()。所以不必实现那个方法。
提供一个tag给Fragment不是只用在无UI的Fragment上面。也可以用在有UI的Fragment上面,但是如果使用无UI的Fragment,那么tag就是唯一的方式找到这个Fragment。如果想得到Fragment,可以使用 findFragmentByTag()。
例子见,FragmentRetainInstance.java
4.管理Fragment
使用FragmentManager管理Fragment。调用getFragmentManager()获得它。FragmentManager可以做的事情:
获得Activity中的Fragment, 用findFragmentById()(用于有UI的Fragment)或者findFragmentByTag()(用于没有UI的Fragment)。
用popBackStack() 方法从栈中pop Fragment(模拟Back按钮)。
用addOnBackStackChangedListener()方法注册一个监听栈的监听器。
更多信息查看FragmentManager类文档。
之前已经展示了用FragmentManager创建一个FragmentTransaction,可以执行事务,比如添加,删除Fragment。
5.执行Fragment事务
使用Fragments的好的特征是在Activity中可以添加,删除,替代,并且可以执行其他动作,来响应用交互。每次一组修改后提交给Activity叫做一个事务。也可以保存事务到后台栈。允许用户经由fragment的变化往回导航(类似于通过activity往后导航)。获得一个FragmentTransaction的实例
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
每个事务是一组变更,并且这组变更是在同一时间执行。可以在给定的事务中设置想要执行的方法,比如 add(), remove(), and replace()。最后调用commint()。调用commint()之前,也许想要调用addToBackStack(),是为了添加事务给Fragment事务的后台栈。Activity管理这个后台栈,并且允许用户返回前一个Fragment的状态,通过点back按钮。
例子,如何替换Fragment,
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
这个例子中,newFragment 代替layout Id指定的Fragment。调用addToBackStack(),这个替代事务被存放到后台栈,所以可以回退事务,通过back键得到之前的Fragment。如果添加了多个修改给事务(比如,add(),remove())并且调用了addToBackStack(),那么在调用comment()之前的所有改变实现前会被当做一个单独的事务,并且back键将把他们一起回退。
添加到FragmentTransaction中改变的顺序不重要,除了下面:
最终必须调用commint()
如果添加多个Fragment到同一个容器,那么添加顺序决定了他们的显示顺序
当执行一个移除Fragment事务的时候,如果不调用addToBackStack(),那么事务提交的时候Fragment将被销毁,并且不能导航回到他。因此,当移除一个Fragment的时候,如果调用addToBackStack(),Fragment将会进入stopped状态,并且如果导航回去会resumed。
注意:对于每一个Fragment事务,可以实现事务动画,在commint前调用setTransition()。
调用commit()不会理解执行事务。它会计划自己在Activity UI线程中的运行。如果有必要,需要在UI线程立即执行提交的事务,可以执行executePendingTransactions()。这么做一般是不必要的,除非事务依附于其他线程的一些工作。
警告:提交事务只可以在Activity保存状态之前(离开Activity的时候)。如果之后提交,将会抛出异常。这是因为,如果Activity需要恢复的时候,提交一个后的状态可能会丢失。这种情况下可以丢失,如果调用commitAllowingStateLoss()。
6.和Activity通信
虽然Fragment是一个被实现为一个独立于Activity的对象,并且可以被使用到多个Activity,一个给定的Fragment实例是直接绑定到包含他的Activity中。特别的,Fragment可以访问Activity通过 getActivity()并且容易执行任务,比如在Activity中得到一个view。
View listView = getActivity().findViewById(R.id.list);
同样的,Activity可以调用Fragment中的方法,通过FragmentManager找到Fragment的引用然后执行方法。比如:ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
7.给Activity创建一个事件回调
一些情况中,需要Fragment共享事件给Activity。一个好的方式是在Fragment里定义一个回调接口并且让Activity实现它。当Activity从接口接受一个回调,可以和其他Fragment共享信息。比如,一个app有两个Fragment在Activity中,一个显示文章列表(Fragment A),另一个显示文章(Fragment B),那么当一个list item被点击,Fragment A 必须告诉Activity,这样它能告诉Fragment B去显示文章,这个例子中,OnArticleSelectedListener 接口声明在Fragment A中:
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
然后拥有Fragment的Activity实现OnArticleSelectedListener 接口并且重写onArticleSelected() 去通知Fragment B更新内容。为了保证Activity实现这个接口,Fragment A的onAttach()回调方法(当添加Fragment到Activity的时候系统会调用此方法)实例化一个OnArticleSelectedListener 的实例通过强转Activity: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 implement OnArticleSelectedListener");
}
}
...
}
如果Activity没有实现接口,Fragment会抛出ClassCastException。成功的话,mListener 这个成员变量保持一个Activity实现OnArticleSelectedListener 后的引用, 所以Fragment A可以通过调用OnArticleSelectedListener 中的方法共享事件给Activity。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);
}
...
}
onListItemClick()传进来的 id参数是点击item的行ID,Activity(或者其他Fragment)通过它获得程序中的文章内容。
8.处理Fragment的生命周期
管理Fragment的生命周期和管理Activity很类似。像Activity一样,Fragment可以存在三种状态:Resumed在运行的Activity中,Fragment是可见的。
Paused
另一个Activity在前端并且获得焦点,Fragment所在的Activity任然可见(前端的Activity是部分透明或者没有覆盖整个屏幕)
Stopped
Fragment不可见。要么宿主Activity已经stopped,要么Fragment被在Activity的后台栈中移除。一个stopped状态的Fragment任然存在的(所有栈和成员信息任然被系统保存)。然而,对于用户是不可见并且如果Activity被销毁那么Fragment也会被销毁。
和Activity一样,可以使用Bundle保存Fragment的状态,比如Activity被销毁了,当Activity被重新创建的时候Fragment的状态也可以还原。可以在onSaveInstanceState()回调方法中保存状态,并且在onCreate(), onCreateView(), or onActivityCreated()回调方法中还原状态。更多关于状态存储看Activity的文旦。
Activity和Fragment最大的不同是他们如何保存到各自的后台栈中。默认情况下,当Activity停止的时候是由系统管理的。然而,Fragment是在一个事务期间执行移除操作的时候,调用addToBackStack()来存储一个Fragment实例,这时Fragment是被存放到Activity的后台栈,并被这个Activity管理。
不用的,Fragment和Activity的生命周期管理是很类似的。所以, managing the activity lifecycle的内容也是适用于Fragment的。需要理解的是Activity如何影响Fragment的生命周期。
警告:如果在Fragment中需要一个Context对象,可以调用getActivity()。然而,getActivity()要小心适用,因为只有在Fragment attached于Activity时才有效。当Fragment还没有attached,或者在最后detached了,getActivity()将返回null。
9.和Activity的生命周期协调工作
Fragment的生命周期受他宿主Activity的生命周期影响,比如,Activity中的生命周期回调方法被调用,那么Fragment的生命周期回调方法也会被调用。比如,Activity onPause()调用了,那么Fragment的onPause()也会被调用。
Fragment有一些额外的生命周期回调,那是和Activity处理的唯一交互,为了执行构建和销毁Fragment的UI。这些额外的回调方法是:
onAttach()
当Fragment被关联到Activity的时候回调。(Activity会被传递到这里)
onCreateView()
当Fragment创建视图的时候回调。
onActivityCreated()
当Activity的onCreate()完了之后,会回调。
onDestroyView()
当Fragment关联的视图被移除的时候回调。
onDetach()
当Fragment不在和Activity关联的时候回调。
Fragment的生命周期流程被宿主Activity所影响,如下图。图中,可以看到Activity中每一个连续的状态对应Fragment中相应的回调方法。比如,当Activity已经收到onCreate(),那么Activity中的Fragment不在会调用onActivityCreated()。
一旦Activity到了resumed状态,可以自由添加和移除Activity的Fragment。因此,只有当Activity在resumed状态的时候,Fragment可以独自的改变其生命周期。
然而,当Activity离开resumed状态的时候,Fragment再次被推倒Activity的生命周期中。