您的位置:首页 > 其它

Fragment平板技术开发(一)

2015-06-18 14:22 411 查看
Fragment是Android3.0引入的新API,可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的生命周期,单独处理自己的输入,在Activity运行的时候可以加载或者移除Fragment模块。 可以把Fragment设计成可以在多个Activity中复用的模块,当开发的应用程序同时适用于平板电脑和手机时,可以利用Fragment实现灵活的布局,改善用户体验。



一、Fragment的特征
1.Fragment总是作为Activity界面的组成部分。Fragment可调用getActvity()方法获取它所在的Activity,调用FragmentManager的findFragmentById()或findFragmentByTag()方法来获取Fragment。其中,fragment的id或tag在其布局文件<fragment../>元素中定义。
2.在Activity运行过程中,可调用FragmentManager的add()、remove()、replace()、方法动态地添加、删除或替换Fragment。
3.一个Activity可以同时组合多个Fragment;反过来,一个Fragment也可能被多个Activity复用;
4.Fragment可以响应自己的输入事件、并拥有自己的声明周期,但它们的生命周期直接被其他所属的Activity的生命周期控制。
二、Fragment的生命周期
因为Fragment必须嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相关的。如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stopped状态,这个Activity中所有的Fragment都不能被启动;如果Activity被销毁,那么它其中的所有Fragment都会被销毁。但是,当Activity在活动状态,可以独立控制Fragment的状态,比如加上或者移除Fragment。当这样进行fragment
transaction(转换)的时候,可以把fragment放入Activity的back stack中,这样用户就可以进行返回操作。
1.Fragment的几个状态
(1)活动状态:当前Fragment位于前台,用户可见、可以获得焦点;
(2)暂停状态:其他Acitvity位于前台,该Fragment依然可见,只是不能获得焦点;
(3)停止状态:该Fragment不可见,失去焦点
(4)销毁状态:该fragment被完全删除,或者Fragment所在的Activity被结束
2.Fragment生命周期
如最常见的就是onCreateView()方法,其作用是返回一个View对象将Fragment显示出来。



三、Fragment开发基本步骤
1.创建Fragement,并设置该Fragment的显示界面
与创建Activity类似,开发者实现的Fragment必须继承Fragment基类,Android提供了4种Fragment:(1)DialogFragment-对话框界面的Fragment;(2)ListFragment-实现列表界面的Fragment;(3)PreferenceFragment-选项设置界面的Fragment;(4)WebViewFragment-WebView界面的Fragment。创建Fragment通常需要实现三个回调方法:
(1)onCreate()
系统在创建Fragment的时候调用这个方法,这里应该初始化相关的组件,一些即便是被暂停或者被停止时依然需要保留的东西。
(2)onCreateView()
当第一次绘制Fragment的UI时系统调用这个方法,必须返回一个View。组件View对应的布局文件,即为该Fragment将会显示的界面。如果Fragment不提供UI也可以返回null。
注意,如果继承自ListFragment,onCreateView()默认的实现会返回一个ListView,所以不用自己实现。
(3)onPause()
当用户离开Fragment时第一个调用这个方法,需要提交一些变化,因为用户很可能不再返回来。
示例1:实现一个Fragment的布局界面。通过onCreateView()方法,将example_fragment布局资源文件设置为该Fragment的显示界面。
源码:
public static class ExampleFragment extends Fragment
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
  Bundle savedInstanceState)
        {
         return inflater.inflate(R.layout.example_fragment,     //加载当前的Fragment对应的资源文件
                            container,                 //父容器控件
                             false);       //*表明是否链接该布局和其父容器。这里设置为false,是因为系统已经插入了这个布局到父控件,设置为true将会产生多余的一个View Group*/ 
         }
}

注释:onCreateView方法中container参数代表该Fragment在Acitivity的父控件;savedInstanceState提供了上一个实例的数据。
2.把一个Fragment加入到Activity中
Fragment不能单独存在,必须依附在Activity上。当Fragment被加入到指定的Activity中时,它会处在对应的容器中。通常,Fragment加载到一个Activity有两种方式:一种是在Activity布局中使用标签<fragment..../>声明;另一种方法是在代码中把Fragment加入到一个Activity的指定容器中。
(1)通过被加载Activity的布局文件将Fragment加载到指定Acitivity
我们只需在指定Activity的布局文件中,添加一个<fragment.../>元素将Fragment作为一个子标签加入即可。

示例2:实现加载一个列表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>


注释:android:name属性为该需要加载的Fragment完整类名(包.类名);android:id属性为该Fragment的唯一标识符ID,我们可以通过ID实现对该Fragment进行添加、删除等操作。

(2)利用FragmentManager和FragmentTransaction将一个Fragment加载到指定Activity的ViewGroup中

当Activity处于活动状态下的时候,可以使用这种方法在Activity的布局中动态地加入Fragment,只需要指定加入这个Fragment的父容器即可。
FragmentManager主要完成获取指定Fragment,将Fragment从后台弹出栈、为后台Fragment注册一个监听器。
FragmentTransaction则完成Fragment的添加、删除、替换等事务,每个FragmentTransaction可以包含多个对Fragment修改,比如包含调用了多了add()、remove()和replace()操作,最后还调用commit()方法提交事务即可。
首先、通过FragmentManager对象获得一个FragmentTransaction对象,借助FragmentTransaction对象实现Acitivity对Fragment执行添加、删除、替换等操作。
FragmentManager fragmentManager=getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//打开事务
其次,将实现的名为BookListFragment的Fragment添加到Activity布局中的容器内
BookListFragment booklistfragment = new BookListFragment(); //创建一个图书列表Fragment
fragmentTransaction.add(R.id.fragment_container, booklistfragment );
//添加图书列表Fragment到标识为fragment_container容器
fragmentTransaction.commit(); //提交事务改变生效-使View容器显示图书列表Fragment
注释1:如果想使应用程序允许用户按BACK返回键回到替换Fragment之前的状态(即上一个Fragment),我们可以将事务添加到back栈。
fragmentTransaction.addtoBackStack(null);
注释2:除了上述添加一个Fragment到Activity的View父容器中,还可以替换或者删除容器中已有的Fragment.调用commit()方法使得FragmentTransaction实例的改变生效。
fragmentTransaction.replace(R.id.fragment_container, booklistfragment);
//替换容器类已有的Fragment
注释3:R.id.fragment_container为当前Activity布局中ID为fragment_container的容器,在Activity界面布局文件中定义。
res/layout/main.xml



3.Fragment与Activity通信
通过第二步将一个Fragment加载到指定的Activity之后,该Fragment必须与Activity交互信息,这就需要Fragment能获取它所在的Activity,Activity也能获取它所包含的任意的Fragment。
1)获取目标对象
(1)Fragment获取它所在的Activity:
调用Fragment的getActivity()方法即可返回它所在的Activity。
(2)Activity获取它所包含的Fragment:
调用Activity关联的FragmentManager的findFragmentById(int id)或findFragmentByTag(String
tag)方法即可获取指定的Fragment。
ExampleFragment fragment =(ExampleFragment)getFragmentManager().findFragmentById(R.id.example_fragment)
注释:我们可以在Activity界面元件中使用<fragment.../>添加Fragment时,可以为<fragment../>元素添加android:name或android:tag属性来标识Fragment,接下来Activity将可以通过findFragmentById(int
id)等方法来获取Fragment。

2)Frament与Activity之间的数据传递
(1)Activity向Fragment传递数据:
在Activity中创建Bundle数据包,并调用Fragment的setArguments(Bundle
bundle)方法即可将Bundle数据包传给Fragment;
(2)Fragment向Activity传递数据或Activity需在Fragment运行中进行实时通信:
在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口.

3)activity响应fragment的事件完全解析
有时,你可能需要fragment与activity共享事件。一个好办法是在fragment中定义一个回调接口,然后在activity中实现这个回调接口。
例如,有个新闻程序的例子,它有一个activity,activity中含有两个fragment。fragmentA显示新闻标题,fragmentB显示标题对应的内容。fragmentA必须在用户选择了某个标题时告诉activity,然后activity再告诉fragmentB,fragmentB就显示出对应的内容(为什么这么麻烦?直接fragmentA告诉fragmentB不就行了?也可以啊,但是你的fragment就减少了可重用的能力。现在我只需把我的事件告诉宿主,由宿主决定如何处置,这样是不是重用性更好呢?)。如下例,
(1)在fragmentA(BookListFragment)中定义OnBookSelectedListener回调接口:

public class BookListFragment extends ListFragment
 {
           private OnBookSelectedListener whichbook; //接口对象
 public interface OnBookSelectedListener
         {
             public void onBookSelected(Integer id); //参数为Map集合的键
         }
        .....
}
(2)
然后在activity实现接口OnBookSelectedListener,在方法onBookSelected()中通知fragmentB(BookDetailFragment
),即Activity从FragmentA获取传入的ID,用来启动FragmentB。

如下所示:
public class SelectBookActivity extends Activity implements BookListFragment.OnBookSelectedListener
{
    ......
     public void onItemSelected(Integer id)
     {
          //a.创建Bundle,准备向Fragment传入参数
          Bundle bundle=new Bundle();
           bundle.putInt(BookDetailFragment.ITEM_ID, id); //装入值id到"item_id"键
          //b.创建BookDetailFragment对象,并项Fragment传入参数
          BookDetailFragment fragment=new BookDetailFragment();
          fragment.setArguments( bundle);
          //c.使用fragment替换book_detail_container容器当前显示的Fragment
          getFragmentManager().beginTransaction()
                                            .replace(R.id.book_detail_container, fragment)
                                            .commit();
          /*注释:这一句等价于....
           * FragmentManager Manager=getFragmentManager();
           * FragmentTransaction Transaction=Manager.beginTransaction();
           * Transaction.replace(R.id.book_detail_container, Manager);
           * Transaction.commit();
           * */
     }
}    <span style="background-color: inherit; line-height: 1.875; font-family: 'Times New Roman';">                                                                                                                      </span>


(3)实现fragmentA(BookListFragment)的onAttach()方法,将fragmentA添加并显示到Activity中

当fragmentA添加到activity中时,会调用fragmentA的方法onAttach(),这个方法中适合检查activity是否实现了OnBookSelectedListener接口,检查方法就是对传入的activity的实例进行类型转换,如果activity没有实现那个接口,fragment抛出ClassCastException异常。如果成功了,mListener成员变量保存OnArticleSelectedListener的实例。于是fragmentA就可以调用mListener的方法来与activity共享事件。
public void onAttach(Activity activity)
 {
      super.onAttach(activity);
      //a.如果Activity中没有实现Callbacks接口,抛出异常
      if(!(activity instanceof Callbacks))
      {
           throw new IllegalStateException("异常:BookListFragment所在的Activity必须实现Callback接口!");
      }
      //把该Activity当成whichbook对象(缺少这一句话,导致出现NullPointerException错误)
       whichbook=( BookListFragment)activity;
 }
(4)在fragmentA中实现onListItemClick()响应activity发出的事件(Fragment向Activity传递ID)
如果fragmentA是一个ListFragment,每次选中列表的一项时,就会调用fragmentA的onListItemClick()方法,在这个方法中调用onBookSelected()来与activity共享事件。onBookSelected()传入的参数id是列表的被选中的行ID,另一个fragment(B)( BookDetailFragment )用这个ID来从程序的ContentProvider中取得标题的内容。

@当用户单击某列表项时激发该回调方法
public void onListItemClick(ListView l, View v, int position, long id) {
      super.onListItemClick(l, v, position, id);
       osition).id);//激发 OnBookSelectedListener接口的onBookSelected方法
 }




总结:

◆FragmentManager:用于在Activity中管理Fragment,比如通过findFragmentById()或findFragmentById()方法获得已存在的Fragment;通过 popBackStack()使Fragment出栈;通过beginTransaction()方法获得FragmentTransaction对象等。

◆FragmentTransaction:用于在Activity中处理Fragment相关事务,比如添加(add)一个Fragment到Activity、从Activity中删除(remove)/替换(replace)一个Fragment。另外,当Activity中发生了FragmentTransaction事务,需要调用commit()方法提交事务使之生效。需要注意的是,在提交事物之前,我们也可以通过
addToBackStack()方法将未改变的状态添加到栈中,以便当用户点击Back返回键时Fragment能够返回未改变的状态。

参考:
http://www.cnblogs.com/mengdd/archive/2013/01/08/2851368.html
/article/1875814.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: