欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

一起学Android之Fragment

程序员文章站 2023-04-06 14:31:05
本文以一个简单的小例子,简述在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,以根据屏幕空间优化用户体验。

一起学Android之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的生命周期有许多相似之处。如下图所示:

一起学Android之Fragment

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: 

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中,实现松耦合。

备注

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