
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对象。
2)设定如何启动另一个Activity。
主要代码如下,也可以参考【例2-2】的项目Example2-2源码的FirstActivity.java。
2.2.3 Intent实现不同页面的传参
在一个Android应用程序中,不同的Activity页面之间经常需要通信。Android利用In-tent的Extra部分来存储它想要传递的数据,用Intent在Activity之间传递数据的基本步骤如下。
1)在发送端传值,构建Intent。
向Intent中添加要传递的参数。
2)在接收端获取传递过来的值。
取出Intent传递的参数。
【例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的主要代码如下。
【代码说明】
●第12行实现向Intent对象添加要传递的信息。
●第13行实现由Intent对象启动的另一个Activity信息。
SecondActivity.java的主要代码如下。
【代码说明】
●第06行代码实现接收从前一个Activity中传递过来的Intent对象。
●第07行代码实现从接收的Intent对象提取前一个Activity传递来的信息。
●第09行代码实现在Activity界面中显示前一个Activity传递来的信息。
4)在虚拟机上运行应用程序,并在第1个Activity中单击按钮进行信息发送,如图2-6a所示,切换到第2个Activity并接收到了来自第1个Activity所传递的信息,如图2-6b所示。
图2-6 Activity传递效果图
a)信息发送 b)信息接收
从本应用程序可以得出,Intent不仅可以在Android系统组件之间实现切换,并且能够在两个Activity页面之间传递参数。
当然,Intent还可以实现其他组件之间的信息传递,这些内容将在后面的章节中进行介绍。