转载!
Intent是一种运行时绑定(run-time binding)机制,它能在程序运行的过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来完成请求。比如,有一个Activity希望打开网页浏览器查看某一网页的内容,那么这个Activity只需要发出WEB_SEARCH_ACTION请求给Android,Android会根据Intent的请求内容,查询各组件注册时声明的IntentFilter,找到网页浏览器Activity来浏览网页。
Intent对象抽象地描述了要执行的操作,其描述的基本内容可以分为组件名称、Action(动作)、Data(数据)、Category(类别)、Extra(附加信息)和Flag(标志位)6部分,下面是详细的介绍。
(1) 组件名称是指Intent目标组件的名称。组件名称是一个ComponentName对象,这种对象名称是目标组件类名和目标组件所在应用程序的包名的组合。组件中包名不一定要和manifest文件
中的包名完全匹配。组件名称是一个可选项。如果Intent消息中指明了目标组件的名称,这就是一个显式消息,Intent会传递给指明的组件。如果目标组件名称并没有指定,Android则通Intent
内的其他信息和已注册的IntentFilter的比较来选择合适的目标组件。
(2) Action描述Intent所触发动作名字的字符串,对于Broadcast Intent来说,Action指被广播出去的动作。理论上Action可以为任何字符串,而与Android系统应用有关的Action字符串以静态字符串常量的形式定义在了Intent类中。列出了当前Android系统中常见的Activity Action Intent的Action
(3) Data描述Intent要操作的数据URI和数据类型。有的动作需要对相应的数据进行处理。比如,对于动作ACTION_EDIT来说,它的数据可以为联系人、短信息等可编辑的URI。而对于
ACTION_CALL来说,它的数据可以是一个tel://格式的电话号码URI。正确设置Intent的数据对于Android寻找系统中匹配Intent请求的组件很重要。如果你使用了ACTION_CALL,但是你的数据却设置成了mailto://格式的URI,那么你所期望的“启动打电话应用程序”这一动作会因为没有与之相对应的应用程序而不会被执行。所以每次使用Intent时,我们都应该留意与设置的Action相关的数据类型和格式。
(4) Category是对被请求组件的额外描述信息。Android也在Intent类中定义了一组静态字符串常量表示Intent不同的类别
(5) 列出了常用的Category常量
(5) Extra当我们使用Intent连接不同的组件时,有时需要在Intent中附加额外的信息,以便将数据传递给目标Activity。比如ACTION_TIMEZONE_CHANGED需要带有附加信息表示新的时区。Extra用键值对结构保存在Intent对象当中,Intent对象通过调用方法putExtras()和getExtras()来存储和获取Extra。Extra是以Bundle对象的形式来保存的,Bundle对象提供了一系列put和get方法来设置、提取相应键值信息。在Intent类中同样为Android系统应用的一些Action所附加信息的键值定义了静态的字符串常量。
EXTRA_BCC 装有邮件密送地址的字符串数组
EXTRA_CC 装有邮件抄送地址的字符串数组
EXTRA_EMAIL 装有邮件发送地址的字符串数组
EXTRA_INTENT 使用ACTION_PICK_ACTIVITY动作时装有Intent选项的Key
EXTRA_KEY_EVENT 触发该Intent的按键的KeyEvent对象
EXTRA_PHONE_NUMBER 使用拨打电话相关Action时,电话号码字符串的Key,类型为String
EXTRA_SHORTCUT_ICON 使用ACTION_CREATE_SHORTCUT在HomeActivity创建快
...
对于明确指出了目标组件名称的Intent,我们称之为“显式Intent”。对于没有明确指出目标组件名称的Intent,则称之为“隐式Intent”。Android系统使用Intent Filter 来寻找与隐Intent相关的对象.
显式Intent直接用组件的名称定义目标组件,这种方式很直接。但是由于开发人员往往并不清楚别的应用程序的组件名称,因此,显式Intent更多用于在应用程序内部传递消息。比如在某
应用程序内,一个Activity启动一个Service。隐式Intent恰恰相反,它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。
清楚了显式Intent和隐式Intent的概念后,我们再来看看决定Intent目标组件的因素。在显式Intent消息中,决定目标组件的唯一要素就是组件名称,因此,如果你的Intent中已经明确定义了目标组件的名称,那么你就完全不用再定义其他Intent内容。而对于隐式Intent则不同,由于没有明确的目标组件名称,所以必须由Android系统帮助应用程序寻找与Intent请求意图最匹配的组件。具体的选择方法是:Android将Intent的请求内容和一个叫做Intent Filter的过滤器比较,Intent Filter中包含系统中所有可能的待选组件。如果Intent Filter中某一组件匹配隐式Intent请求的内容,那么Android就选择该组件作为该隐式Intent的目标组件.
Android 如何知道应用程序能够处理某种类型的Intent 请求呢? 这需要应用程序在AndroidManifest.xml中声明自己所含组件的过滤器(即可以匹配哪些Intent请求)。一个没有声
明Intent Filter的组件只能响应指明自己名字的显式Intent请求,而无法响应隐式Intent请求。而一个声明了Intent Filter的组件既可以响应显式Intent请求,也可以响应隐式Intent请求。在通过和Intent Filter比较来解析隐式Intent请求时,Android将以下三个因素作为选择的参考标准。
? Action
? Data
? Category
而Entra和Flag在解析收到Intent时是并不起作用的。
Intent Filter
应用程序的组件为了告诉Android自己能响应、处理哪些隐式Intent请求,可以声明一个甚至多个Intent Filter。每个Intent Filter描述该组件所能响应Intent请求的能力——组件希望接收什么类型的请求行为,什么类型的请求数据。比如之前请求网页浏览器这个例子中,网页浏览器程序的Intent Filter就应该声明它所希望接收的Intent Action是WEB_SEARCH_ACTION,以及与之相关的请求数据是网页地址URI格式。
如何为组件声明自己的Intent Filter? 常见的方法是在AndroidManifest.xml文件中用属性<Intent-Filter>描述组件的Intent Filter。
前面我们提到,隐式Intent和Intent Filter进行比较时的三要素是Intent的动作、数据以及类别。实际上,一个隐式Intent请求要能够传递给目标组件,必要通过这三个方面的检查。如果任何一方面不匹配,Android都不会将该隐式Intent传递给目标组件。接下来我们讲解这三方面检查的具体规则。
1.动作测试
<intent-filter>元素中可以包括子元素<action>,比如:
<intent-filter>
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
</intent-filter>
一条<intent-filter>元素至少应该包含一个<action>,否则任何Intent请求都不能和该<intent-filter>匹配。
如果Intent请求的Action和<intent-filter>中个某一条<action>匹配,那么该Intent就通过了这条<intent-filter>的动作测试。
如果Intent请求或<intent-filter>中没有说明具体的Action类型,那么会出现下面两种情况。
(1) 如果<intent-filter>中没有包含任何Action类型,那么无论什么Intent请求都无法和这条<intent-filter>匹配;
(2) 反之,如果Intent请求中没有设定Action类型,那么只要<intent-filter>中包含有Action类型,这个Intent请求就将顺利地通过<intent-filter>的行为测试。
2.类别测试
<intent-filter>元素可以包含<category>子元素,比如:
<intent-filter . . . >
<category android:name="android.Intent.Category.DEFAULT" />
<category android:name="android.Intent.Category.BROWSABLE" />
</intent-filter>
只有当Intent请求中所有的Category与组件中某一个IntentFilter的<category>完全匹配时,才会让该Intent请求通过测试,IntentFilter中多余的<category>声明并不会导致匹配失败。一个没有指定任何类别测试的IntentFilter仅仅只会匹配没有设置类别的Intent请求。
3.数据测试
数据在<intent-filter>中的描述如下:
<intent-filter . . . >
<data android:type="video/mpeg" android:scheme="http" . . . />
<data android:type="audio/mpeg" android:scheme="http" . . . />
</intent-filter>
<data>元素指定了希望接受的Intent请求的数据URI和数据类型,URI被分成三部分来进行匹配:scheme、authority和path。其中,用setData()设定的Inteat请求的URI数据类型和scheme必须与IntentFilter中所指定的一致。若IntentFilter中还指定了authority或path,它们也需要相匹配才会通过测试。
讲解完Intent基本概念之后,接下来我们就使用Intent激活Android自带的电话拨号程序,通过这个实例你会发现,使用Intent并不像其概念描述得那样难。