android API Guides------------------Fragment

博客为 有时个哥 原创,如需转载请标明出处:http://blog.youkuaiyun.com/ls703/article/details/43983451
Fragment

 

在activity里面,一个Fragment代表了一种行为或是用户界面的一部分。在一个activity里面,你可以组合利用多个Fragment创建出一个多窗口的UI,并且这些Fragment是可以在多个activity重复利用的。你可以认为Fragment是activity的一个的模块,并且这个模块拥有自己的生命周期,可以接受自己的输入事件,并且在activity运行时可以进行添加或移除(有点像一个子activity,你可以在不同的activity中去重复利用它。

 

Fragment必须是嵌入到activity中的,它的生命周期也直接受这个activity的生命周期的影响。例如当activity进入pause状态,则所有的Fragment也都进入到这个状态中。当activity被销毁了,则所有的Fragment也都是被销毁了。然而当一个activity在运行状态时(在被回复的生命周期状态),你可以独立的去操作每一个Fragment,比如去添加或移除他们。当你创建执行完一个Fragment时,你也可以把他放到back栈中,让activity能更好的管理他们。back栈里存放的是已经创建执行完的Fragment的记录。这个back栈允许用户去回退到上一个Fragment事务,通过点击后退按钮。

 

当你添加一个Fragment到activity中,作为activity布局的一部分时,这个Fragment是存在于activity的视图结构中的一个ViewGrop的容器中的,并且这个Fragment要定义一个自己的布局文件。你可以通过在activity的布局文件中声明,作为一个<fragment> 元素来在activity中插入一个Fragment,或在你的代码里把他添加到一个存在的ViewGroup容器中。当然,Fragment也不一定是总被activity需求成为其界面的一部分,它也可以作为一个没有界面的“无形的工作者”存在于activity中。

这个文档描述的是怎样去创建你的应用去使用Fragment,包括当Fragment被添加到back栈中时,在activity中把事件分享给其他的activity或其他Fragment时,去和activity的action bar关联操作时,等等情况时,怎样去维护他们的状态;

 

 

Design Philosophy(设计原理)

 

android 引入Fragment这个概念是在android 3.0(API level 11),主要是为了给大屏幕提供更多动态的灵活的界面设计。例如平板。因为平板的屏幕比手机的大,它有更大的空间去组合和交换UI控件。Fragment的这种设计让你不需要去管理复杂变化的视图层次。把一个activity的布局分割成多个Fragment,你就能够在activity运行的时候去改变activity的外观并且可以把这些变化保存到back栈中,通过activity来管理它们。

例如一个新闻应用能使用一个位于左边的Fragment来显示新闻列表,在右边的Fragment来显示文章的内容,两个Fragment同时显示在同一个activity中,并且每一个Fragment都有自己的生命周期的回调方法和处理自己的传入事件。从而代替用一个activity来选择文章,用另一个activity去读这篇文章,用户能在同一个activity中选择并且阅读文章。如在图1所示,在平板电脑中。

你应该把每一个fragment 设计为一个模块化的并且可重复利用的组件。也就是说,因为每一个fragment有自己的布局和自己的生命周期回掉行为,你可以在多个活动中使用一个fragment,因此你应该设计成可重用的并且要避免直接操作从一个fragment到另一个fragment的操作。这一点是非常重的,因为一个模块化的fragment允许你对于不同的屏幕大小可以改变你的fragment的组合。当你的应用需要都支持平板和手机时,你能在不同的布局配置中重复使用你fragment,基于可用的屏幕空间去优化你的用户体验。例如,在手机中,你可能需要一个单身的fragment来提供一个单一的窗口界面,当在同个activity中超过一个以上的操作不能够适应时。

图一:一个例子--------怎样两个由Fragment定义的模块在平板中的一个activity中来组合展示,在手机设计中是被分离开的。

 

例如,继续说新闻客户端的例子,这个应用在平板设备上运行时,能够唉activityA中嵌入两个Fragment。然而在手机上,他没有足够的空间去放开两个Fragment,以至于activityA只能包含一个Fragment来显示文章的列表,当用户选择文章时,开始启动一个activityB,它包含两个Fragment来显示文章的内容。所以这个应用通过在不同的重合中重复利用fragment来同时支持平板和手机,如图一。

关于在不同配置上设计不同Fragment组合的应用的更多信息,请勿看Guides中的Supporting Tablets and Handsets

Creating a Fragment(创建Fragment)

 

创建一个Fragment,你必须创建一个Fragment的子类(或一个已经存在的子类)。Fragment类的代码和activity的很相似。他和activity一样,包含回掉方法,例如,onCreate(),onStart(),onPause(), andonStop()。事实上,如果你要把一个存在的android应用同改变成使用Fragment,你只要简单的把activity的回调方法中把代码移动到Fragment中对应的回调方法中就可以了。

通常,你应该实现下面的生命周期方法:

oncreate()

          当创建Fragment创建时,系统调用。在你的实现中应该初始化Fragment的基本元素组件,当Fragment位于位于paused 或 stopped状态时,能够保存下来,需要时能重新唤醒,进入resume状态。

onCreateView()

           当用户界面第一次去绘制时,系统调用。去绘画一个Fragment界面,你必须在这个方法中返回一个view,也就是你Fragment的布局的根源。如果Fragment没有返回的UI时,你可以放回null。

onPause()

系统调用这个方法,作为fragment离开应用的第一迹象(尽管它不总是意味着fragment被销毁了)。这通常是在当前会话中保存你的更改并保存的地方(因为你的用户可能不会返回回来了)。

很多应用的每一个fragment至少应该事先这三个方法。当然也有几个其他的方法你也应该使用它们去处理fragment生命周期的不同阶段。关于生命周期的部分将会在Handling the Fragment Lifecycle.这一部分中讨论的更多。

 

 

这里也有几个fragment延伸出来的子类,来代替fragment的使用:

 

DialogFragment

           展示一个浮动的dialog。在activity中使用这个类来创建dialog是一个很好的去代替dialog辅助方法的选择,因为你可以把fragment dialog存放到back栈中通过activity来管理,允许用户回到这个fragment。

ListFragment

          显示一个通过adapter(例如  SimpleCursorAdapter),来管理的一个list列表,与ListActivity类似。他提供几个方法来管理列表的布局。例如onListItemClick()回掉方法来处理点击事件。

PreferenceFragment

         显示选择对象的层次列表。和PreferenceActivity类似。当你的应用中药创建一个“settings”时可以用到它。

 

Adding a user interface(添加用户界面)

fragment通常作为activity的用户界面的一部分,并为把自己的界面贡献给activity。

 

要提供fragment的布局,你必须实现onCreateView()这个回掉方法,这个方法是在fragment绘制自己布局的时候系统调用它。这个方法必须返回一个view,也就是fragment布局的根源。

 

注意:如果你的fragment是一个ListFragment子类,他默认的实现时返回一个listView从onCreateView()中,因此你就不需要在实现它。

 

对于在onCreateView()返回的View布局,你是可以从一个以声明的XML然后inflate这个xml布局文件来得到。为了帮你这样做,onCreateView()方法为你提供了一个LayoutInflater对象。

 

例如,这里有一个Fragment的子类,从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);
    }
}

 

真个container参数被传递给你的Fragment将要插入到的ViewGroup(来自activity布局)中。savedInstanceState参数是一个Bundle集合,如果这个Fragment被resumed,它将提供以前Fragment事例的数据。(回复状态将在Handling the Fragment Lifecycle讨论的更多)。

 

这inflate()方法的三个参数:

。要被inflate的资源Id

。ViewGrop是被inflate的布局的父类。通过container是重要的,是为了系统去获得被inflate的布局的根布局的布局参数。

。boolean用于表示在inflate过程中,inflate的布局是否要附属于这个ViewGroup(第二个参数)。(如果是这样的话,这里要设置成false,因为填充布局第二个参数以是填充到父类布局中,如果是true的话,就会在最后就是长生一个冗余的布局)。

 

现在你看的是怎么去创建一个Fragment布局,接下来就是怎样奖Fragment添加到你的activity中。

 

Adding a fragment to an activity(添加Fragment到activity)

 

通常fragment的UI布局提供给activity,它被嵌入到activity中作为所有activity的界面层次结构的一部分。这里有两种方法能把Fragment添加到activity的布局中。

 

。通过在声明activity布局文件中的fragment来添加

    这种方法,可以去直接指定fragment的属性。例如下面是含有两个fragment的activity布局文件

<?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的布局,并且去调用每一个frgament中的onCrreateView()方法,去检索得到每一个Fragment的布局。然后系统插入fragment返回的布局来替代<fragment>元素部分。

 

注意:每一个fragment都会请求一个唯一的标识符,系统可以去通过这个标识符去还原他们的布局,如果activity被重新启动时(也能通过标识符去得到fragment来做一些处理,例如去移除他们)。这里有三种提供fragment资源Id的方法:

。android:id属性便签,设置fragment唯一的资源id

。通过设置android:tag属性值,设置fragment唯一的字符串(tag)

。如果你使用了之前的两种方法,那么系统就可以使用在view容器的id资源了

 

。用代码创建把它添加到一个存在的viewgroup中

在activity运行的任何时候,你都能够在activity中添加fragment。你仅仅需要去指定一个view容器去存放fragment。

 

如果要在activity中去处理fragment的操作(如添加,移除,替换),你就需要使用FragmentTransaction提过的api接口。你可以在activity中的到FragmentTransaction的实例,就像下面:

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


 

然后你就可以是用add()方法去添加fragment了,把fragment添加到指定的view容器中 。例如:

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

 

add()方法中的第一个参数是要存放fragment的ViewGroup的资源id,第二个参数是要添的fragment对象。

 

如果你一旦使用FragmentTransaction对做出一些改变,那你必须要调用commit()方法,使这些改变生效。

 

添加没有UI界面的fragment

在上面的例子中介绍了怎样去添加一个有界面的fragment,然后你也能去在activity中使用一个在后台运行的没有界面的fragment。

 

添加fragment,你则需要使用add(Fragment,String)这个方法来添加(是通过提供Fragment唯一的tag值,而不是view 的Id资源)。这种添加方式因为没有和activity的布局产生联合交互,所以你就不需要去实现onCreateView()方法。

通过提过tag值并不是严格的只能提供没有UI界面的Fragment的tag,你也可以去提供一个有UI界面的Fragment的tag。但是,没有UI界面的Fragment是通过这个tag值来找到声明它的。如果你想要去得到他,则需要在后面调用findFragmentByTag()方法。

如果像看没有界面的在activity中后台运行的Fragment例子,你可以去看FragmentRetainInstance.java中的简单例子。

 

Managing Fragments(管理Fragment)

在activity中管理Fragment,你则需要使用待FragmentManager,在activity中你可以通过调用getFragmentMananger()方法来得到它。

下面是你可以使用getFragmentMananger来做的一些事情:

。通过findFragmentById()(为activity提供Ui界面的Fragment)或findFragmentByTag()(没有界面的Fragment)来得到一个已经存在的Fragment

。使用popBackStack()把Fragment放入到back栈中(模拟用户的后退命令)

。使用addOnBackStackChangedListener()来注册一个监听back栈变化的监听

 

如果想了解关于FragmentManager的更多地方法和信息,你可以去查看FragmentManager类的文档。

 

正如上面所展示的,你可以使用FragmentManager去得到一个FragmentTransaction对象。FragmentTransaction可以去执行一些过于fragment的操作,如添加或移除fragment。

 

Performing Fragment Transactions(fragment的相关处理)

 这是一个非常重要的特性,在你的activity中你可以对fragment进行添加,移除,替换或者是用这些fragment来做一些操作来响应用户的交互。你可以使用FragmentTransaction的api里面的方法 去提交每一组的变化(被称作事务)并可以执行它们。你也可以把这些事务保存到back栈中,让activity去管理,允许用户做返回操作(有点像activity的返回操作)。

你可以通过FragmentManager来回的一个是实例。像下面代码中的:

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


每一个事务是一组在同一时间你想去执行的变化。你可以通过add(),remove()和replace()来设定你的事务的那组变化。然后,应用这些事务时,要调用commit()提交它们。

在调用commit()之前你可以调用addToBackStack()这个方法,来吧事务添加到fragment事务back栈中。这个back栈可以通过activity管理,并允许用户点击返回键时退回到上一个fragment状态。

 

例如:怎样去用另一个fragment替换当前的fragment,并把被替换的fragment状态保存到back栈中。

// 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对象替换在指定id资源为R.id.fragment_container 的容器中的fragment,通过调用addToBackStack(),保存被替换的食物,使用户在点击返回键时能够倒退事务,取出上一个fragment。如果你在事务中要添加多样的变化(例如一个添加,一个移除),并且调用addToBackStack(),并把这些变化在电泳commit()前,作为单一任务存放在back栈中,点击返回键时一起倒退它们。

 

这个你添加的顺序是不重要的,被期望做的是:

。你必须最后调用commit()方法

。如果你添加多样的事务到同一个容器中,然后你添加的顺序决定了它们在图层结构中显示的顺序。

 

如果你执行一个删除fragment的事务时,你如果没有调用addToBackStack()的方法,则事务被提交时这个fragment将会被销毁。,用户就不能够回退它们。然而,如果你调用了addToBackStack() 方法,则fragment将会是被停止,如果点击回退,则会重新激活它。

Tip:对于每一个fragment,在电泳commit()提交之前,你可以通过调用setTransition()来设置一个事务动画。

 

调用commit()方法,不是立即就执行了事务。相反,当线程能够去执行这些时,则它将会在activity的UI线程(主线程)中安排它执行。如果需要理解执行的话,你可以从主线程中调用executePendingTransactions(),通过commit()方法 去提交事务。通常是没必要这么做的,除非事务时依赖于其他的线程。

 

警告:用commit()提交事务要在活动之前保存活动的状态(当用户离开activity时)。如果你要是在之后提交事务,则将会抛出一个异常。这是因为如果activity需要去修复的时候,提交之后的状态会丢失。在使用commitAllowingStateLoss().方法这种情况下丢失提交是可以的。

 

Communicating with the Activity(在activity中交互)

 

尽管fragment是被作为一个在activity中独立的对象来实现的并且可以在多个activity中使用,但是一个给定的fragment实例适合包含他的activity相关联的。

 

特别是,fragment可以通过getActivity() 方法去访问activity实例,很容易的去完成像这种在activity布局中找到相应view的操作。

 

View listView = getActivity().findViewById(R.id.list);

 

同样的,你的activity也可以通过用findFragmentById() 或findFragmentByTag()FragmentManager里获得一个fragment的引用参数来调用fragment里面的方法。例如:

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


Creating event callbacks to the activity(创建事件回掉)

 

在一些情况下,以可能需要fragment去分享activity的事件。一个好的方法是在fragment里面去创建回掉接口,让activity去实现它。当activity通过接口接收回掉时,就能够去分享其他fragm里的信息了。

 

例如:一个新闻应用在activity里有两个fragment,一个显示新闻列表(fragmentA),一个显示文章内容(fragment B),让后当点击列表项时,fragment A要把这个列表项告诉给activity,以至于他能告诉fragment B去显示文章内容。这种情况要在fragment中去生命OnArticleSelectedListener接口。

 

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 A中的事件告知fragment B。为了确保activity实现这个接口,fragment A中的onAttach()回掉方法去实例化从activity的onAttach()方法传递过来的OnArticleSelectedListener的实例。


 

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能够调用activity实现的OnArticleSelectedListener接口的方法 去分享事件。例如,Fragment是一个ListFragment的扩展,每一次用户点击列表的一项时,系统都会调用OnArticleSelectedListener(),然后调用onArticleSelected()在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参数是来确定点击的项的定位id,让activity(或Fragment)用来从应用的ContentProvider里取这对应的文章。

关于内容提供者的更多信息,请去查看Content Providers文档。

 

Adding items to the Action Bar(把项目添加到操作栏)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值