Fragments

来源:互联网 发布:英国女王大学 知乎 编辑:程序博客网 时间:2024/05/22 14:38

1、一个Fragment代表一个在Activity中用户节目的一个行为或者一部分,你可以把多个Fragment在一个Activity中聚合成一个

成一个UI并在多个Activity中重用他。你可以把Fragment当作一个模块化的Activity,他有自己的生命周期,能相应自己的输入时间

并在可以在Activity运行时添加或者删除。

2、一个Fragment必须始终嵌入在一个Activity中,Fragment的生命周期受到宿主活动的生命周期的影响。例如,当Activity暂停时,

所有的Fragment都会被暂停,当Activity被destory时,Fragment也会被destory。并且你执行fragment事务时,你还可以把他

添加到后台堆栈,返回堆栈允许用户通过按下返回按钮来回到上一个fragment

3、Fragment生命周期

(1)onCreate()

当Fragment被创建时,系统调用这个方法,在你的fragment中,你应该初始化fragment的基本组件

(2)onCreateView()

当fragment第一次绘制他的用户界面时,系统会调用这个方法。为了给你的fragment绘制UI,你必须在这个方法中返回一个

view对象来作为你fragment的根布局,你也可以返回空如果你的fragment不需要UI界面

(3)onPause

当系统调用这个方式时则表明用户离开这个fragment,你通常应该在这个地方保存一些数据


4、常见fragment

(1)DialogFragment

显示一个浮动对话框。

(2)PreferenceFragment

显示一个列表,类似PreferenceActivity,当你创建一个设置的activity这是十分有用的

(3)ListFragment

显示一个列表,通过适配器


5、添加到用户界面

(1)为fragment提供一个布局,你必须实现onCreateView()方法。注:如果你实现的是ListFragment,他的onCreateView()默认返回一个ListView,所以可以不用实现他

而onCreateView会返回一个布局,你可以用定义在XML中的文件填充他,为了帮助你做到这一点,onCreateView返回了一个LayoutInflate对象

例如,下面展示从example_fragment.xml载入一个布局文件

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参数是你的fragment布局将要插入的父布局(从Activity的layout中来的)


6、inflate方法主要有三个参数

Resource ID:想要填充的布局的资源ID,container:要填充布局的父布局、传进去的container是十分重要的,这以便于系统将布局参数应用到填充布局的根布局

boolean:这个boolean值表示填充的布局是否应该依附在父布局上(第二个参数),在上面这种情况是false,因为系统已经将填充布局插入container中了,如果传入true则会在最后多出一个viewgroup

并且如果container为false或者boolean为false,都只会显示子布局

7、把fragment添加到Activity中

(1)在Activity的布局文件中声明fragment

在这种情况下,你可以指定fragment的布局属性,例如:

<?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的布局时,会实例化每一个fragmenr并且调用onCreateView()方法来返回每一个fragment的布局,系统用这些返回的布局插入到视图中来代替这些<fragment>


注意:每个fragment都要求有一个唯一的标识符以便于系统可以重启他当activity重启时(你也可以用着id来操作fragment),有以下三种方式可以给fragment提供一个ID

1)android:id   2)android:tag  3)如果以上两种都没有,那么系统会用容器视图的ID


(2)以代码方式添加到ViewGroup

当你在Activity中操作fragment事务时,你必须使用FragmentTransaction,你可以通过以下方法在Activity中获取实例

ragmentManager fragmentManager = getFragmentManager()FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

然后你就可以使用add方法插入fragment

ExampleFragment fragment = new ExampleFragment();fragmentTransaction.add(R.id.fragment_container, fragment);fragmentTransaction.commit();

add方法的第一个参数fragment应该放置的ViewGroup,用资源id来表示,第二个是要添加的fragment,一旦你的FragmentTransaction发生变化,必须要用commit使其生效。


8、添加没有用户界面的Fragment

要添加一个没有用户界面的fragment,从Activity中添加Fragment使用add(Fragment,String)(String是指fragment的tag,而不是id),这样就可以添加该fragment,但是因为并没有和Activity产生联系,所以onCreateView()没有被回调,所以不需要实现该方法


不是只有没有UI的fragment能使用tag来标识,有UI的也可以用tag来标识,但是如果fragment没有UI,tag是唯一能够标识他的方法,如果你想在之后的Activity中使用它的话,可以用findFragmentbyTag()方法


可以参考<sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java


9、管理Fragment

管理Fragment需要使用FragmentManager,可以在activity中调用getFragmentManager获得。

你可以用FragmentManager做以下工作:

1)可以使用findFragmentById()得到在Activity中的fragment(在Activity中提供用户界面),使用findFragmentByTag()(没有提供用户界面)

2)用popBackStack()把fragment弹出返回栈,模拟用户的返回操作

3)注册监听返回栈的变化监听器,用addOnBackStackChangedListener()


10、执行Fragment事务

你可以从FragmentManager从获取一个FragmentTransaction

FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
每一组事务都是要同一时间执行更改,且必须调用commit()

在你调用commit()方法前,你可能想调用addToBackstack()方法来把事务添加到Fragment Transation的返回栈中,这个返回栈由activity管理,并且允许用户返回到之前的fragment状态。

例如,这里表现来如何用一个fragment代替另一个fragment,并把之前那个保存在返回栈


// Create new fragment and transactionFragment 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 stacktransaction.replace(R.id.fragment_container, newFragment);transaction.addToBackStack(null);// Commit the transactiontransaction.commit();
在这个例子中,newFragment取代了其他的fragment(如果有的话)。并且通过调用addToBackStack()方法,把replace事务保存到返回栈,让用户可以逆转事务并返回之前的fragment.

如果你做了多个更改并且调用了addToBackStack(),那么所有在你调用commit()方法前的变化都会作为一个单独的事务被添加到返回栈中,并且返回键可以恢复他们.

在FragmentTransaction中做的更改顺序是没有差别的,除了以下两种情况:

1)你最后需要commit()

2)你在同一个容器中添加了多个fragment,那么你添加fragment的顺序决定来他们在视图层次的顺序


如果你不调用add'T'o'BackStack()方法当你执行一个删除fragment事务,那么这个fragment将会无法返回在事务被commit()。如果在你移除fragment时调用addToBackStack(),fragment将会停止并且重新启动如果用户按返回键


对于每个fragment transaction,你都可以添加过渡动画,通过setTransition()方法在你commit之前


注意:你必须在activity保存状态前(即当用户离开activity)使用commit()提交事务,如果不这么做,将会抛出一个异常。因为提交后的状态可能会丢失,在这种情况下,最好使用commitAllowingStateLoss()


11、与Activity交互

具体来说,fragment可以通过getActivity()来获取activity实例并且很容易执行一些类似在activity布局中寻找视图的任务

View listView = getActivity().findViewById(R.id.list);
同样的,你的Activity可以通过通过FragmentManager中获取fragment的引用通过findFragmentById或者findFragmentByTag()

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

12、创建回调事件

在某些情况下,你的fragment可能需要与activity分享一些事件,一个好的方法是在fragment中定义一个回调接口并要求与其相连的activity实现他,当activity通过接口受到回调时,他可以在必要时与其他fragment共享信息。

比如,一个新闻应用程序在一个activity有两个fragment,一个用来显示文章列表(fragment A),另一个来显示文章(fragment B),然后fragment必须通知activity当列表中的一项被选中时以便于能通知fragment来显示文章。在这种情况下,可以在fragment A中声明一个OnArticleSelected接口。


public static class FragmentA extends ListFragment {    ...    // Container Activity must implement this interface    public interface OnArticleSelectedListener {        public void onArticleSelected(Uri articleUri);    }    ...}
然后activity实现了这个接口并且重写这个方法来通知fragment B来自fragment A的消息,并且为了确保activity实现来这个接口,fragment A的回调方法OnAttach()(当把这个fragment添加到activity时系统会调用这个方法)中通过把传入OnAttach()的activity强转成OnArtcleSelected来实例化
来实例化

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则会抛出一段异常。如果成功来,mListener的成员变量持有继承了OnArtcleSelected的activity的引用,所以fragment A就可以与activity共享事件通过在监听中定义的方法。例如,如果fragment A继承于ListFragment,每次用户单击列表项,系统调用OnListItemListener(),然后再调用OnArtcleSelected()

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);    }    ...}

13、把item添加到Action bar

你的fragment可以把菜单栏添加到activity的选项菜单(比如Action Bar)通过实现onCreateOptionsMenu()方法。为了使这个方法被回调,你必须调用setHasOptionsMenu在OnCreate()中,来表明这个fragment想要在在菜单栏中添加条目(否则fragment的onCreateOptionsMenu不会受到回调)。

在你把fragment的菜单栏接到已经存在的菜单栏后,这个fragment也可以受到onOptionsItemSelected回调。

你也可以在你的fragment布局中注册一个视图来提供一个上下文菜单通过registerForContextMenu(),当用户打开上下文菜单时,fragment的onCreateContextMenu()会被回调,当用户选择其中一栏时,onContextItemSelected()会被回调


注意:虽然你的fragment会接收到菜单栏选择事件,但是activity会最先接收到这个回调当用户选择栏目时,如果activity实现的onItemSelected没有处理这个选择事件的话,那么该事件则会被传递给fragment


14、处理fragment的生命周期

fragment主要存在三种状态:

1)Resume:这个fragment在运行的activity中可见

2)Paused:另一个activity在前台并且有焦点,但这个activity仍然可见(前台的activity没有覆盖整个屏幕或者是部分透明)

3)Stopped:fragment是不可见的,无论是绑定的activity被停止或者fragment被移除但是被加到返回栈中。一个被停止的fragment仍然存在的(所有状态和成员信息被保存在系统中),但是他对用户不再是可见的并且当activity被杀死的时候他也会被杀死


跟activity一样,你可以在bundle中保留fragment的状态,如果activity的进程被杀死,你可以在onSaveInstance中保存并在onCreate(),OnCreateView(),OnActivityCreate(),中恢复。


activity和fragment生命周期中最大的不同就是他们存储在不同的返回栈。默认情况下,activity在停止时会被放入由系统管理的返回栈。但是,只有当你明确的使用addToBackStack()要求时,fragment在被移除后才会被放入由他们绑定的activity管理的返回栈中。


注意:如果你的fragment需要一个context对象,你可以通过调用getActivity()获得,但是要注意调用getActivity()时必须已经绑定activity,否则会返回空。


15、与Activity的生命周期相协调

fragment有一些额外的生命周期方法,fragment需要与activity处理一些独特的交互来执行一些操作比如创建和销毁fragment的UI,这些额外的方法有:

1)onAttach():当activity与fragment绑定时调用

2)onCreateView():当创建与该fragment的视图层次时调用

3)onActivityCreate():当activity调用Oncreate()返回时调用

4)onDestoryView():当相关的fragment的视图层次被移除时

5)onDetach():当fragment与activity解除绑定时




一个fragment的生命周期是受到activity影响的,如上图所示,在这图中,你可以看到每个生命周期回调方法如何决定一个fragment可能接收到的回调。

一旦activity达到resume状态,你才可以自由的添加和删除fragment,也只有在这个状态,一个fragment的生命周期才能独立改变。



0 0
原创粉丝点击