Android移动应用开发实用教程
上QQ阅读APP看书,第一时间看更新

2.2 Intent

Intent是Android中的重要组件,可以被认为是不同组件之间通信的“媒介”或者“信使”。使用它可以使Activity、Service、BroadcastReceiver和ContentProvider等核心组件之间互相调用,协调工作,最终组成一个真正的Android应用。如果没有它,Android应用的各个模块就像一座座“孤岛”,根本不可能构成一个完整的应用系统。本节主要从3个方面进行介绍:Intent组件的概念、实现Acrtivity页面跳转,以及Intent实现不同页面的传参。

2.2.1 Intent组件的概念

在Android架构中,Intent本身也是一个对象,负责对一个执行操作的抽象数据结构进行描述。在Intent协助这些组件之间的通信中,Android则根据此Intent的描述,负责找到并将Intent传递给对应的组件,并完成组件的调用。这个抽象的数据结构主要由如下的内容和属性构成。

1.组件名称(ComponentName)

Intent的组件名称是可选的,如果填写,Intent对象会发送给指定组件名称的组件,否则,也可以通过其他Intent信息定位到适合的组件。组件名称是一个ComponentName类型的对象,该对象又包括:目标组件完整的类名,如com.example.project.app.FreneticActivity;在manifest.xml文件中设置的包名,组件的包名和manifest.xml中定义的包名。组件的名称可通过setComponent()方法、setClass()方法或setClassName()方法设置,通过getComponent()方法读取。

2.动作(Action)

一个以字符串命名的动作通过Intent传递并将被执行,或者在广播Intent中,表示发生的或者要报告的动作。

不同的动作对应不同的数据类型,比如ACTION_EDIT动作可能对应的是用于编译文档的URI,而ACTION_CALL动作则应该包含类似于tel:xxx的URI。多数情况下,数据类型可以从URI的格式中获取,当然,Intent也支持使用setData()方法和setType()方法来指定数据的URI及类型。一个Intent对象的动作通过setAction()方法设置,通过getAction()方法读取。

查看更多的动作定义请参考Android API中的Intent类。

就Android平台而言,URI主要分为3部分:scheme、authority和path。其中authority又分为host和port。格式如下:scheme://host:port/path。

3.数据(Data)

Data起到表示数据和数据MIME类型的作用。不同的Action是与不同的Data类型配套的。比如,Action是ACTION_EDIT,那么Data要包含所要编辑文档的URI。如果Action是ACTION_CALL,Data可能是“tel:”前缀后面跟电话号码,再比如Action是ACTION_VIEW,Data是以“http:”开头的URI,则应该是显示或者下载该URI的内容。

在匹配Intent到处理它的组件过程中,Data(MIME类型)类型是很重要的。例如,一个组件能够显示图像数据,不应该被调用去播放一个音频文件。

在许多情况下,数据类型能够从URI中推测出来,特别是content:URIs,它表示位于设备上的数据且被内容提供者(Content Provider)控制。但是类型也能够显示地设置,例如,setData()方法指定数据的URI,setType()方法指定MIME类型,setDataAndType()方法指定数据的URI和MIME类型。通过getData()方法读取URI,getType()方法读取类型。

4.类别(Category)

既然不同的动作应该对应不同的数据类型,那么不同的动作也应该由不同类别的Activi-ty组件来处理,比如CATEGORY_BROWSABLE表示该Intent应该由浏览器组件来打开,CATEGORY_LAUNCHER表示该Intent由应用初始化Activity处理,而CATEGORY_PREFER-ENCE则表示处理该Intent的组件应该是系统配置界面。此外,消息对象(Intent)可以使用addCategory()方法添加一种类型,而一个Intent对象也可以包含多种数据类型。

更多种类的常量定义请参考Android API中的Intent类。

addCategory()方法用于添加一个种类到Intent对象中,removeCategory()方法用于删除一个之前添加的种类,getCategories()方法用于获取Intent对象中的所有种类。

5.附加信息(Extras)

Extras可以看作一个Map,可通过键值对为Intent组件提供一些附加的信息。

例如,一个ACTION_TIMEZONE_CHANGE的Intent有一个“time-zone”的附加信息,标识新的时区;ACTION_HEADSET_PLUG有一个“state”附加信息,标识头部现在是否塞满或未塞满。如果自定义了一个SHOW_COLOR动作,颜色值可以设置在附加的键值对中。

一般使用putExtras()方法和getExtras()方法安装和读取键值对中的信息。

6.标志(Flags)

在Intent中增加Flag,可以指示Android系统如何去启动一个活动(例如,活动应该属于哪个任务)和启动之后如何处理它(例如,它是否属于最近的活动列表)。所有这些标志都定义在Intent类中。

在Android应用中,Intent的使用方式通常有两种:显式Intent和隐式Intent。

显式Intent直接用组件的名称定义目标组件,这种方式很直接。但是由于开发人员往往并不清楚别的应用程序的组件名称,因此,显式Intent更多用于在应用程序内部传递消息。例如在某应用程序内,一个Activity启动一个Service等。

隐式Intent恰恰相反,它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。由于没有明确的目标组件名称,所以必须由Android系统帮助应用程序寻找与Intent请求意图最匹配的组件。

Android系统寻找与Intent请求意图最匹配的组件具体的选择方法是:Android将Intent的请求内容和一个名为IntentFilter的过滤器比较,IntentFilter包含系统中所有可能的待选组件。如果IntentFilter中某一组件匹配隐式Intent请求的内容,那么Android就选择该组件作为该隐式Intent的目标组件。

Android如何知道应用程序能够处理某种类型的Intent请求呢?这需要应用程序在Mani-fest.xml中声明自己所含组件的过滤器(即可以匹配哪些Intent请求)。

一个没有声明IntentFilter的组件只能响应指明自己名称的显式Intent请求,而无法响应隐式Intent请求。而一个声明了IntentFilter的组件既可以响应显式Intent请求,也可以响应隐式Intent请求。在通过和IntentFilter比较来解析隐式Intent请求时,Android将以下3个因素作为选择的参考标准:Action、Data和Category,而Extra和Flag在解析收到的Intent时并不起作用。

2.2.2 实现Activity页面跳转

有两个Activity,当想要从第一个Activity跳转到另一个Activity时,通常是在第一个Ac-tivity中单击按钮或者其他操作,此时需要调用第一个Activity的startActivity(Intent)方法,跳到哪个Activity及Activity具体要做什么都是由Intent对象决定的。

在一个Activity当中启动另一个Activity的方法分为两部分。

1)在第一个Activity中添加监听器setOnClickListener(),具体的监听方法是实现On-ClickListener接口,在此方法中建立intent对象。

978-7-111-51177-9-Chapter02-16.jpg

2)设定如何启动另一个Activity。

978-7-111-51177-9-Chapter02-17.jpg

主要代码如下,也可以参考【例2-2】的项目Example2-2源码的FirstActivity.java。

978-7-111-51177-9-Chapter02-18.jpg

2.2.3 Intent实现不同页面的传参

在一个Android应用程序中,不同的Activity页面之间经常需要通信。Android利用In-tent的Extra部分来存储它想要传递的数据,用Intent在Activity之间传递数据的基本步骤如下。

1)在发送端传值,构建Intent。

978-7-111-51177-9-Chapter02-19.jpg

向Intent中添加要传递的参数。

978-7-111-51177-9-Chapter02-20.jpg

2)在接收端获取传递过来的值。

978-7-111-51177-9-Chapter02-21.jpg

取出Intent传递的参数。

978-7-111-51177-9-Chapter02-22.jpg

【例2-3】Example2-3 Intent传递参数示例。

1)创建项目文件Example2-3Intent01,然后在Src中分别创建两个Activity:FirstActivi-ty.java和SecondActivity.java。

2)在resource→layout中分别创建两个Activity对应的布局文件,并且编辑项目的全局配置文件AndroidManifest.xml声明这两个Activity组件。

3)编写两个Activity类文件,详细内容请参考项目源码。

FirstActivity.java的主要代码如下。

978-7-111-51177-9-Chapter02-23.jpg

【代码说明】

●第12行实现向Intent对象添加要传递的信息。

●第13行实现由Intent对象启动的另一个Activity信息。

SecondActivity.java的主要代码如下。

978-7-111-51177-9-Chapter02-24.jpg

【代码说明】

●第06行代码实现接收从前一个Activity中传递过来的Intent对象。

●第07行代码实现从接收的Intent对象提取前一个Activity传递来的信息。

●第09行代码实现在Activity界面中显示前一个Activity传递来的信息。

4)在虚拟机上运行应用程序,并在第1个Activity中单击按钮进行信息发送,如图2-6a所示,切换到第2个Activity并接收到了来自第1个Activity所传递的信息,如图2-6b所示。

978-7-111-51177-9-Chapter02-25.jpg

图2-6 Activity传递效果图

a)信息发送 b)信息接收

从本应用程序可以得出,Intent不仅可以在Android系统组件之间实现切换,并且能够在两个Activity页面之间传递参数。

当然,Intent还可以实现其他组件之间的信息传递,这些内容将在后面的章节中进行介绍。