Android
中提供了Intent
机制来协助应用间的交互与通讯。Intent
负责对应用中一次操作的动作以及附加数据进行描述,Android
则根据此Intent
的描述,负责找到对应的组件,将Intent
传递给调用的组件,并完成组件的调用。
Intent
不仅可用于应用程序之间,也可用于应用程序内部的Activity
或Service
之间的交互。因此Intent
在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。SDK
给出了Intent
作用的表现形式:
- 通过
startActivity
或Activity.startActivityForResult
启动一个Activity
。 - 通过
startService
启动一个服务,或者通过bindService
和后台服务交互。 - 通过广播方法(比如
sendBroadcast
、sendOrderedBroadcast
和sendStickyBroadcast
)发给broadcast receivers
。
Intent属性的设置
Action
SDK
中定义了一些标准的动作,Action
就是表示了要执行操作的字符串(比如查看或选择),其对应着Intent Filter
中的action
标签<action />
。常见的Activity Action Intent
常量如下:
常量名称 | 常量值 | 意义 |
---|---|---|
ACTION_MAIN |
android.intent.action.MAIN |
应用程序入口 |
ACTION_VIEW |
android.intent.action.VIEW |
显示数据给用户 |
ACTION_ATTACH_DATA |
android.intent.action.ATTACH_DATA |
指明附加信息给其他地方的一些数据 |
ACTION_EDIT |
android.intent.action.EDIT |
显示可编辑的数据 |
ACTION_PICK |
android.intent.action.PICK |
选择数据 |
ACTION_CHOOSER |
android.intent.action.CHOOSER |
显示一个Activity 选择器 |
ACTION_GET_CONTENT |
android.intent.action.GET_CONTENT |
获得内容 |
ACTION_DIAL |
android.intent.action.GET_CONTENT |
显示打电话面板 |
ACITON_CALL |
android.intent.action.DIAL |
直接打电话 |
ACTION_SEND |
android.intent.action.SEND |
直接发短信 |
ACTION_SENDTO |
android.intent.action.SENDTO |
选择发短信 |
ACTION_ANSWER |
android.intent.action.ANSWER |
应答电话 |
ACTION_INSERT |
android.intent.action.INSERT |
插入数据 |
ACTION_DELETE |
android.intent.action.DELETE |
删除数据 |
ACTION_RUN |
android.intent.action.RUN |
运行数据 |
ACTION_SYNC |
android.intent.action.SYNC |
同步数据 |
ACTION_PICK_ACTIVITY |
android.intent.action.PICK_ACTIVITY |
选择Activity
|
ACTION_SEARCH |
android.intent.action.SEARCH |
搜索 |
ACTION_WEB_SEARCH |
android.intent.action.WEB_SEARCH |
Web 搜索 |
ACTION_FACTORY_TEST |
android.intent.action.FACTORY_TEST |
工厂测试入口点 |
常见的BroadcastIntent Action
常量如下:
常量名称 | 描述 |
---|---|
ACTION_TIME_TICK |
系统时间每过一分钟发出的广播 |
ACTION_TIME_CHANGED |
系统时间通过设置发生了变化 |
ACTION_TIMEZONE_CHANGED |
时区改变 |
ACTION_BOOT_COMPLETED |
系统启动完毕 |
ACTION_PACKAGE_ADDED |
新的应用程序apk 包安装完毕 |
ACTION_PACKAGE_CHANGED |
现有应用程序apk 包改变 |
ACTION_PACKAGE_REMOVED |
现有应用程序apk 包被删除 |
ACTION_UID_REMOVED |
用户id 被删除 |
Data
此处所说的Intent
中的data
指的是URI
对象和数据的MIME
类型,其对应着Intent Filter
中的data
标签<data />
。
一个完整的URI
由scheme
、host
、port
、path
组成,格式是<scheme>://<host>:<port>/<path>
,例如content://com.example.project:200/folder/subfolder/etc
。URI
就像一个数据链接,组件可以根据此URI
获得最终的数据来源。通常将URI
和action
结合使用,比如我们将action
设置为ACTION_VIEW
,应该提供将要被编辑修改的文档的URI
。
当创建了一个Intent
对象的时候,除了指定URI
之外,指定数据的MIME
类型也很重要。例如一个Activity
能够显示图片,但是不能够播放视频,显示图片的URI
和播放视频的URI
可能很类似,为了不让Android
误将一个含有视频URI
的Intent
对象传递给一个只能显示图片的Activity
,我们需要在该Activity
的Intent Filter
中指定MIME类型为图片(例如<data android:mimeType="image/*" ... />
),并且还要给Intent
对象设置对应的图片类型的MIME
,这样Android
就会基于URI
和MIME
类型将Intent
传递给符合条件的组件。有个特例,如果URI
使用的是content:
协议,那么这就说明URI
所提供的数据将来自于本地设备,即数据由ContentProvider
提供,这种情况下Android
会根据URI
自动推断出MIME
类型,此种情况我们无需再自己指定MIME
类型。
Intent
的Action
和Data
属性匹配如下:
Action属性 | Data属性 | 说明 |
---|---|---|
ACTION_VIEW |
content://contacts/people/1 |
显示id 为1 的联系人信息 |
ACTION_DIAL |
content://contacts/people/1 |
将id 为1 的联系人电话号码显示在拨号界面中 |
ACITON_VIEW |
tel:123 |
显示电话为123 的联系人信息 |
ACTION_VIEW |
http://www.google.com |
在浏览器中浏览该网站 |
ACTION_VIEW |
file://sdcard/mymusic.mp3 |
播放MP3
|
ACTION_VIEW |
geo:39.2456,116.3523 |
显示地图 |
type
type
是数据类型,用于显式指定Intent
的数据类型MIME
。一般Intent
的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
category
category
包含了关于组件如何处理Intent
的一些其他信息。例如LAUNCHER_CATEGORY
表示Intent
的接受者应该在Launcher
中作为*应用出现;而ALTERNATIVE_CATEGORY
表示当前的Intent
是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。其他的category
如下:
Constant | Meaning |
---|---|
CATEGORY_BROWSABLE |
The target activity can be safely invoked by the browser to display data referenced by a link. For example, an image or an e-mail message. |
CATEGORY_GADGET |
The activity can be embedded inside of another activity that hosts gadgets. |
CATEGORY_HOME |
The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed. |
CATEGORY_LAUNCHER |
The activity can be the initial activity of a task and is listed in the top-level application launcher. |
CATEGORY_PREFERENCE |
The target activity is a preference panel. |
component
component
(组件)指定Intent
的目标组件的类名称。通常Android
会根据Intent
中包含的其它属性的信息,比如action
、data
、type
、category
进行查找,最终找到一个与之匹配的目标组件。但是如果component
这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent
的其它所有属性都是可选的。
extras
extras
(附加信息)是其它所有附加信息的集合。使用extras
可以为组件提供扩展信息,比如如果要执行发送电子邮件
这个动作,可以将电子邮件的标题、正文等保存在extras
里,传给电子邮件发送组件。有的Intent
需要靠URI
携带数据,有的Intent
是靠extras
携带数据信息。
你可以通过调用Intent
对象的各种重载的putExtra(key,value)
方法向Intent
中加入各种键值对
形式的额外数据,也可以直接创建一个Bundle
对象,向该Bundle
对象传入很多键值对
,然后通过调用Intent
对象的putExtras(Bundle)
方法将其这些键值对设置到Intent
对象中。
显式和隐式Intent
理解Intent
的关键之一是理解清楚Intent
的两种基本用法:一种是显式的Intent
,即在构造Intent
对象时就指定接收者;另一种是隐式的Intent
,即Intent
的发送者在构造Intent
对象时,并不知道也不关心接收者是谁,有利于降低发送者和接收者之间的耦合。
对于显式Intent
,Android
不需要去做解析,因为目标组件已经很明确;Android
需要解析的是那些隐式Intent
,通过解析,将Intent
映射给可以处理此Intent
的Activity
、IntentReceiver
或Service
。
显式的Intent
:如果Intent
中明确包含了要启动的组件的完整类名(包名及类名),那么这个Intent
就是explict
(显式的)。使用显式Intent
最典型的情形是在你自己的App
中启动一个组件,因为你自己肯定知道自己的要启动的组件的类名。比如,为了响应用户操作通过显式的Intent
在你的App
中启动一个Activity
或启动一个Service
下载文件。
隐式的Intent
:如果Intent
没有包含要启动的组件的完整类名,那么这个Intent
就是implict
(隐式的)。虽然隐式的Intent
没有指定要启动的组件的类名,但是一般情况下,隐式的Intent
都要指定需要执行的action
。通常情况下,隐式的Intent
只用在当我们想在自己的App
中通过Intent
启动另一个App
组件的时候,让另一个App
组件接收并处理该Intent
。例如你想在地图上给用户显示一个位置,但是你的App
又不支持地图展示,这时你可以将位置信息放入到一个Intent
中,然后给它指定相应的action
,通过这样隐式的Intent
请求其他的地图型的App
(例如Google Map
)来在地图中展示一个指定的位置。隐式的Intent
也体现了Android
的一种设计哲学:我自己的App
无需包罗万象所有功能,可以通过与其他App
组合起来,给用户提供很好的用户体验。而连接自己的App
与其他App
的纽带就是隐式Intent
。
当创建了一个显式Intent
去启动Activity
或Service
的时候,系统会立即启动Intent
中所指定的组件。
当创建了一个隐式Intent
去使用的时候,Android
系统会将该隐式Intent
所包含的信息与设备上其他所有App
的manifest
文件中注册组件的Intent Filters
进行对比过滤,从中找出满足能够接收处理该隐式Intent
的App
和对应的组件。如果有多个App
中的某个组件都符合条件,那么Android
会弹出一个对话框让用户选择需要启动哪个App
。
Intent Filter
Intent Filter
即Intent
过滤器,一个组件可以包含0
个或多个Intent Filter
。Intent Filter
是写在App
的manifest
文件中的,其通过设置action
或uri
数据类型等指明了组件能够处理接收的Intent
的类型。如果你给你的Activity
设置了Intent Filter
,那么这就使得其他的App
有可能通过隐式Intent
启动你的这个Activity
。反之,如果你的Activity
不包含任何Intent Filter
,那么该Activity
只能通过显式Intent
启动。由于我们一般不会暴露出我们组件的完整类名,所以这种情况下,其他的App
基本就不可能通过Intent
启动我们的Activity
了(因为它们不知道该Activity
的完整类名),只能由我们自己的App
通过显式Intent
启动。