Intent 是一个消息传递对象,我们可以使用它启动其他应用组件完成特定的任务。
我们可以通过 Intent 来启动以下三个组件:
public void startActivity(Intent intent)
public ComponentName startService(Intent service)
public boolean bindService(Intent service, ServiceConnection conn, int flags)
public void sendBroadcast(Intent intent)
public void sendOrderedBroadcast(Intent intent, String receiverPermission)
sendStickyBroadcast(Intent intent)
Intent 携带的信息大概有以下几点:
setComponent()
、setClass()
、setClassName()
或 Intent 构造函数设置组件名称setAction()
或 Intent 构造函数为 Intent 指定操作setData()
setType()
setDataAndType()
同时显式设置二者addCategory()
指定类别putExtra()
方法添加数据putExtras()
将Bundle 插入 Intent 中addFlags()
方法添加标志位注: 1.启动 Service 时应该始终指定组件名称。 否则无法确定哪项服务会响应 Intent,且用户无法看到哪项服务已启动。 2.若要同时设置 URI 和 MIME 类型,请勿调用 setData() 和 setType(),因为它们会互相抵消彼此的值。 3.Intent 类将为标准化的数据类型指定多个 EXTRA_* 常量。例如,使用 ACTION_SEND 创建用于发送电子邮件的 Intent 时,可以使用 EXTRA_EMAIL 键指定“目标”收件人,并使用 EXTRA_SUBJECT 键指定“主题”。
Intent 分为两种类型:
显式 Intent 就是直接指定要启动的组件的类名,一般用于应用内部组件调用,这里暂不赘述。
隐式 Intent 不直接指明要启动的组件,而是通过指定要进行的操作,让系统为我们找出匹配的组件,
比如这样:
Uri uri = Uri.parse("smsto:18789999999");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SENDTO);
intent.setData(uri);
intent.putExtra("sms_body", "Hello");
startActivity(intent);
上述代码构建了一个 Intent,然后为它设置了 action, data 和 extra 数据,然后调用了 startActivity()
。
接着系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(在这里即:含 ACTION_SENDTO
操作并携带短信数据的 Intent ):
而在检查每个 Activity 能否处理 Intent 的过程中,需要访问 Intent 过滤器(IntentFilter)。
我们可以在 AndroidManifest.xml 中给 Activity 设置一个 IntentFilter 属性,比如这样:
<activity
android:name=".activity.launchmode.SingleTaskActivity"
android:alwaysRetainTaskState="true"
android:label="singleTask"
android:launchMode="singleTask"
android:taskAffinity="top.shixinzhang.task2">
<intent-filter>
<action android:name="top.shixinzhang.action.test"/>
<category android:name="top.shixinzhang.category.test"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
IntentFilter 中可以设置 action, category 和 data 三种过滤信息,每一种信息都可以有多个。
一个 Activity 也可以有多个 IntentFilter,相当于多了几个过滤器,被筛选到的可能就更大了。
<activity
android:name=".activity.launchmode.SingleTaskActivity"
android:alwaysRetainTaskState="true"
android:label="singleTask"
android:launchMode="singleTask"
android:taskAffinity="top.shixinzhang.task2">
<intent-filter>
<action android:name="top.shixinzhang.action.test"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="top.shixinzhang.category.test"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="myapp.mycompany.com"
android:scheme="myapp"/>
</intent-filter>
</activity>
上面的代码为该 Activity 多增加了一个过滤器,这使得在加载特定 URI 时,它可以被当做浏览器使用。
我们将分别介绍三种过滤信息的匹配规则。
action 可以理解为一个组件具备功能、可以进行什么操作。系统为我们提供了很多内置的 action,当然也可以自定义。
一个 Intent-filter 中可以有多个 action,就好比一个人有多种才能。
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>
Intent 中的 action 至少有一个与过滤器的匹配,才能调用这个过滤器所在的组件,否则无法命中。
以上述 intentFilter 为例,startActivity(intent)
中的 intent 至少要有 android.intent.action.EDIT
和 android.intent.action.VIEW
中的一个 action ,然后也可以有不匹配的 action。
注意:区分大小写。
列一些常用的系统内置 action 如下:
action 名称 | 作用 | 备注 |
---|---|---|
android.intent.action.MAIN | 标识 Activity 为一个程序的开始 | |
android.intent.action.CALL | 呼叫指定的电话号码 | |
android.intent.action.DIAL | 用拨号面板 | |
andriod.intent.action.ALL_APPS | 列出所有的应用 | |
android.intent.action.ANSWER | 处理呼入的电话 | |
android.intent.action.VIEW | 显示用户的数据 | 通用,可以是电话、浏览器等 |
android.intent.action.SENDTO | 发送消息 | 可以是短信、彩信、邮件等 |
android.intent.action.EDIT | 对给定数据以编辑的形式访问 | |
android.intent.action.PICK | 从列表中选择信息 | 一般用于选择联系人或者图片等 |
android.intent.action.CHOOSER | 显示一个Activity选择器 | 比如常见的选择分享到哪里 |
注意: 1.android.intent.action.VIEW 根据 data 的数据类型打开相应的 Activity 比如 tel:13400010001 会打开拨号程序,http://www.baidu.com则会打开浏览器等 2.android.intent.action.SENDTO 更多 action 请见官方文档:https://developer.android.com/reference/android/content/Intent.html
category 即分类,和 action 一样,一个过滤器可以包含多个分类:
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
...
</intent-filter>
和 action 匹配规则(有一个匹配即可)不同的是,category 匹配时,要求你的 Intent 中的 category 必须和过滤器中声明的完全匹配。
以上述 intentFilter 为例,startActivity(intent)
中的 intent 的分类不能是 android.intent.category.DEFAULT
和 android.intent.category.BROWSABLE
以外的。
注意: Android 会自动将
android.intent.category.DEFAULT
类别传递给startActivity()
和startActivityForResult()
的所有隐式 Intent。 因此即使startActivity(intent)
中不传任何分类,也可以命中上述过滤器。
系统为我们提供了很多 category,同时我们也可以自定义。
注意:自定义分类时不要忘记在 AndroidManifest.xml 中添加 android.intent.category.DEFAULT
,原因就是上面提到的,系统会为 startActivity()
中添加这个分类。
下面是一些系统提供的常见 category(图片转自:http://www.2cto.com/kf/201603/492421.html):
data 表示该组件可以支持的数据格式与类型。
同样,一个过滤器也可以有多个 data:
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
...
</intent-filter>
一个 data 由两部分组成:
mimeType 指的是支持的数据类型与格式,常见的有:
/ 号前面的是数据类型,后面是具体格式。
scheme 就是常见的 URI 格式:
<scheme>://<host>:<port>/<path>
具体部分介绍及重要性如下:
比如:
http://www.baidu.com:80/search/info
file://emulator/0/sdcard/shixinzhang
在 intent-filter 中,声明 scheme 必须从前往后,逐步缩小范围。
你可以只声明一个协议,这表示该协议下的所有数据你都可以处理;同样也可以只声明主机地址,这表示使用该协议,访问该主机下的所有数据你都可以处理。
scheme 和 mimeType 组成一个 data。而 data 的匹配规则就是:intent 中的 data 至少可以匹配过滤器中的一个。
也就是说:
content
或者 file
的 scheme 才行,因为 intent-filter 默认包含这两个 scheme注意 intent-filter 默认的 content
或者 file
的 scheme ,它表示默认组件能够从文件中或内容提供程序获得本地数据。
比如下面的 intent-filter,它表示该组件可以从内容提供商处获得并显示图像数据:
<intent-filter>
<data android:mimeType="image/*" />
...
</intent-filter>
另一常见的配置是 scheme 只声明协议,同时声明数据类型的过滤器。
例如,下文中的 元素向 Android 指出,组件可从网络中检索视频数据以执行操作:
<intent-filter>
<data android:scheme="http" android:mimeType="video/*" />
...
</intent-filter>
如果把组件比作一个安卓程序员,我们需要三个条件来筛选出我们想要的那位:
如果当前设备中没有能够匹配你发送到 startActivity() 的隐式 Intent,则调用将会失败,且应用会崩溃。
因此我们需要对 Intent 对象调用 resolveActivity():
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
//验证当前 Intent 是否可以被处理
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}
《Android 开发艺术探索》 https://developer.android.com/reference/android/content/Intent.html https://developer.android.com/guide/components/intents-filters.html?hl=zh-cn