一起学Android之Fragment

Posted hsiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起学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中,实现松耦合。

备注

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

以上是关于一起学Android之Fragment的主要内容,如果未能解决你的问题,请参考以下文章

Android Fragment 在布局中声明,如何设置参数?

布局中声明的Android Fragment,如何设置参数?

Android之Fragment的优点和作用

Android 片段生命周期

寒假学干货之------ 初学者关于fragment_main(碎片的困扰)

Android之Fragment的概述和使用