• 一起学Android之Fragment


    概述

    本文以一个简单的小例子,简述在Android开发中,Fragment的常见用法,仅供学习分享使用,如有不足之处,还请指正。

    什么是Fragment?

    Fragment代表一个功能或者用户界面的一部分。一个Activity可以由多个Fragment组成多窗格UI,一个Fragment也可以重用在多个Activity中。你可以把Fragment作为Activity的一个模块,它有自己的生命周期,接收自己的 输入事件,当Activity运行时可以动态的添加和删除,类似于‘sub Activity’。

    Fragment必须始终作为Activity的一部分,它的生命周期受到宿主Activity生命周期的影响。如:当Activity暂停时,其包含的所有Fragment也都会暂停;当Activity销毁时,其包含的所有Fragment也会被销毁;但是当Activity运行时,你可以独立的操作Fragment,如添加和删除;

    Fragment设计理念

    androidandroid 3.0api等级11)中引入了Fragment,主要是为了支持大屏幕(如平板电脑)上更具活力和灵活性的ui设计。因为平板电脑的屏幕比手机大得多,所以有更多的空间来组合和交换ui组件。通过将Activity的布局划分为Fragment,就能够在程序运行时修改Activity的外观,并在由活动管理的后堆栈中保存这些更改。

    例如,一个新闻应用App,可以用一个Fragment显示左侧的文章列表,用另一个Fragment显示右侧的文章----两个Fragment同时出现在一个Activity中,而每个Fragment都有自己的生命周期及回调方法集合,并处理自己的用户输入事件。因此,用户可以在相同的Activity中选择文章,而不是分开单独使用不同的Activity,如图1的平板版式所示。

    应该将每个Fragment设计成模块化和可重用的页面组件。也就是说,由于每个Fragment有自己的生命周期,回调函数,布局和行为,所以可以在多个Activity中包含同一个FragmentFragment应该设计为重用,避免在一个Fragment中直接操作引用另一个Fragment。这一点特别重要,因为一个模块化的Fragment可以通过不同的组合来适应不同屏幕大小。在应用程序同时支持平板电脑和手机时,可以在不同的布局配置中重用Fragment,以根据屏幕空间优化用户体验。

    1一个例子,说明两个由Fragment定义的UI模块如何在平板上设计为一个Activity中显示,但在手机上则分开显示。

    涉及知识点

    涉及知识点如下:

    • Fragment 所有自定义Fragment的父类。
    • FragmentManager Fragment管理器对象,用来动态新增和替换Fragmentd对象。
    • FragmentTransaction 表示一个Fragment管理事务,必须以commit()结束。
    • onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 方法,返回Fragment对应的布局视图。
    • getFragmentManager() 返回一个Fragment管理器对象。

    创建一个Fragment

    如果要创建一个自定义Fragment,必须创建一个Fragment的子类,并且必须实现onCreateView()方法,通过LayoutInflater将布局文件填充到Fragment中,如下所示:

     1 public class RightFragment extends Fragment {
     2 
     3     private TextView tvMsg;
     4 
     5     @Override
     6     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     7                              Bundle savedInstanceState) {
     8         // Inflate the layout for this fragment
     9         Log.i("TAG", "------------Right-----------onCreateView: ");
    10         View view= inflater.inflate(R.layout.fragment_right, container, false);
    11         tvMsg= (TextView) view.findViewById(R.id.tv_msg);
    12         return view;
    13     }
    14 }

    Fragment生命周期

    Fragment的生命周期和Activity的生命周期有许多相似之处。如下图所示:

    Activity和Fragment回调函数输出内容如下所示:

     1 05-30 22:16:02.207 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onAttach: 
     2 05-30 22:16:02.207 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onCreate: 
     3 05-30 22:16:02.207 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onCreateView: 
     4 05-30 22:16:02.216 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onAttach: 
     5 05-30 22:16:02.216 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onCreate: 
     6 05-30 22:16:02.216 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onCreateView: 
     7 05-30 22:16:02.218 29479-29479/com.hex.demofragment E/TAG: ------------Main-----------onCreate: 
     8 05-30 22:16:02.218 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onActivityCreated: 
     9 05-30 22:16:02.218 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onActivityCreated: 
    10 05-30 22:16:02.219 29479-29479/com.hex.demofragment E/TAG: ------------Main-----------onStart: 
    11 05-30 22:16:02.219 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onStart: 
    12 05-30 22:16:02.219 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onStart: 
    13 05-30 22:16:02.224 29479-29479/com.hex.demofragment E/TAG: ------------Main-----------onResume: 
    14 05-30 22:16:02.224 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onResume: 
    15 05-30 22:16:02.224 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onResume: 
    16 05-30 22:16:06.188 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onPause: 
    17 05-30 22:16:06.188 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onPause: 
    18 05-30 22:16:06.189 29479-29479/com.hex.demofragment E/TAG: ------------Main-----------onPause: 
    19 05-30 22:16:06.756 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onStop: 
    20 05-30 22:16:06.756 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onStop: 
    21 05-30 22:16:06.756 29479-29479/com.hex.demofragment E/TAG: ------------Main-----------onStop: 
    22 05-30 22:16:06.757 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onDestroyView: 
    23 05-30 22:16:06.757 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onDestroy: 
    24 05-30 22:16:06.757 29479-29479/com.hex.demofragment I/TAG: ------------Left-----------onDetach: 
    25 05-30 22:16:06.757 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onDestroyView: 
    26 05-30 22:16:06.757 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onDestroy: 
    27 05-30 22:16:06.757 29479-29479/com.hex.demofragment I/TAG: ------------Right-----------onDetach: 
    28 05-30 22:16:06.757 29479-29479/com.hex.demofragment E/TAG: ------------Main-----------onDestroy: 
    View Code

    Activity中添加Fragment

    Fragment是作为Activity的一部分而存在的,有两种方法可以将Fragment添加到Activity的布局文件中:

    静态添加Fragment

    Activity的布局文件中直接声明Fragment,在这种情况下,您可以为Fragment指定布局属性,就像它是视图控件一样。例如,这里是包含两个片段的活动的布局文件:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout
     3     xmlns:android="http://schemas.android.com/apk/res/android"
     4     xmlns:tools="http://schemas.android.com/tools"
     5     android:layout_width="match_parent"
     6     android:layout_height="match_parent"
     7     android:orientation="horizontal"
     8     tools:context="com.hex.demofragment.MainActivity">
     9    <fragment
    10        android:tag="left"
    11        android:id="@+id/left_fragment"
    12        class="com.hex.demofragment.LeftFragment"
    13        android:layout_width="200dp"
    14        android:layout_height="match_parent"
    15        android:layout_weight="1"></fragment>
    16     <fragment
    17         android:tag="right"
    18         android:id="@+id/right_fragment"
    19         class="com.hex.demofragment.RightFragment"
    20         android:layout_width="300dp"
    21         android:layout_height="match_parent"
    22         android:layout_weight="2"></fragment>
    23 </LinearLayout>

    如上所示:class 表示需要在视图中显示的fragment类,当系统创建Activity时,就会实例化Fragment并调用onCreateView方法,显示对应的布局文件。android:name和class表示的功能是一样的,需要其中一个即可。

    备注:每个Fragment都需要一个唯一的标识符,如果Activity被重新启动的话,系统可以用它来恢复Fragment。

    有三种方法可以为Fragment提供id:

    • 提供android:id带有唯一的ID属性。
    • 提供android:tag带有唯一字符串的标签属性。
    • 如果没有提供前面两个中的任何一个,系统将使用容器视图的id。
    动态添加Fragment

    Activity处于运行状态时,都可以将Fragment添加到页面布局中,只需要有一个ViewGroup用来存放即可。如下所示:

     1 //FragmentManager是Activity内部用来与Fragment进行交互的接口
     2 FragmentManager fm =  getFragmentManager();
     3 FragmentTransaction  ft=fm.beginTransaction();
     4 //将左侧Fragment和Frame控件关联起来
     5 left=new LeftFragment();
     6 left.setTransData(transData);
     7 ft.add(R.id.fl_left,left);
     8 right=new RightFragment();
     9 ft.add(R.id.fl_right,right);
    10 ft.commit();

    如果要管理Activity中的Fragment,需要使用碎片管理器(FragmentManager),可以通过Activity中的getFragmentManager()方法来获得对象。

    Fragment之间的传值

    Fragment 作为独立的可重用的用户模块,应尽量避免相互引用,所以如何实现之间相互传值,就显得很重要,本文采用接口回调的方式进行传值。

    具体如下:

    1、定义一个传值接口,如下所示:

    1 public interface ITransData {
    2     public void transData(Bundle bundle);
    3 }

    2、在需要传值的Fragment中,定义接口属性对象,如下所示,左侧(LeftFragment):

     1 private ITransData mTransData;
     2 
     3 public void setTransData(ITransData transData){
     4     this.mTransData=transData;
     5 }
     6 
     7 @Override
     8 public View onCreateView(LayoutInflater inflater, ViewGroup container,
     9                          Bundle savedInstanceState) {
    10 
    11     View view = inflater.inflate(R.layout.fragment_left, container, false);
    12     Button tv= (Button) view.findViewById(R.id.bn_left);
    13     tv.setOnClickListener(new View.OnClickListener() {
    14         @Override
    15         public void onClick(View v) {
    16             if(mTransData!=null){
    17                 Bundle bundle=new Bundle();
    18                 bundle.putString("name","我是左边");
    19                 mTransData.transData(bundle);
    20             }
    21         }
    22     });
    23     return view;
    24 }

    3、Activity中,实现ITransData接口,并传给LeftFragment进行调用:

     1 @Override
     2 protected void onCreate(Bundle savedInstanceState) {
     3     super.onCreate(savedInstanceState);
     4     setContentView(R.layout.activity_main2);
     5     ITransData transData=new TransData();
     6     //FragmentManager是Activity内部用来与Fragment进行交互的接口
     7     FragmentManager fm =  getFragmentManager();
     8     FragmentTransaction  ft=fm.beginTransaction();
     9     //将左侧Fragment和Frame控件关联起来
    10     left=new LeftFragment();
    11     left.setTransData(transData);//将接口传递给LeftFragment
    12     ft.add(R.id.fl_left,left);
    13     right=new RightFragment();
    14     ft.add(R.id.fl_right,right);
    15     ft.commit();
    16 }

    4、在接口函数中调用获取左侧传回来的值,并调用RightFragment方法传递值。

     1 protected class TransData implements ITransData
     2 {
     3     @Override
     4     public void transData(Bundle bundle) {
     5         String name=bundle.getString("name","空");
     6         if(right!=null){
     7             right.setTransData(name);
     8         }
     9     }
    10 }

    至此Fragment之间传值介绍完毕,总结一句话:Fragment通过接口传值,接口的实现在Activity中,实现松耦合。

    备注

    沧海月明珠有泪,蓝田日暖玉生烟。

  • 相关阅读:
    synchronized wait notify 生产者消费者
    Thread start0 启动分析 一图看懂
    Mysql 存储过程造测试数据
    Springboot Bean循环依赖问题
    事务分析(二) 事务传播
    事务分析(一) 事务回滚
    Mysql 事务隔离级别分析
    Bug 佛祖镇楼
    Springboot+Swagger
    Springboot跨域 ajax jsonp请求
  • 原文地址:https://www.cnblogs.com/hsiang/p/10960598.html
Copyright © 2020-2023  润新知