本片博客原文路径:https://blog.csdn.net/u011240877/article/details/71305797
读完本文你将了解:
Intent
Intent 携带的信息
Intent 的类型
隐式 Intent
Intent 过滤器 IntentFilter
IntentFilter 的匹配规则
action 的匹配规则
category 的匹配规则
data 的匹配规则
总结过滤规则
注意
Thanks
Intent
Intent 是一个消息传递对象,我们可以使用它启动其他应用组件完成特定的任务。
我们可以通过 Intent 来启动以下三个组件:
Activity
public void startActivity(Intent intent)
Service
public ComponentName startService(Intent service)
public boolean bindService(Intent service, ServiceConnection conn, int flags)
BroadcastReceiver
public void sendBroadcast(Intent intent)
public void sendOrderedBroadcast(Intent intent, String receiverPermission)
sendStickyBroadcast(Intent intent)
Intent 携带的信息
Intent 携带的信息大概有以下几点:
组件名称 mComponent
可以使用 setComponent()、setClass()、setClassName() 或 Intent 构造函数设置组件名称
如果没有名称就是隐式的 Intent
要进行的操作 mAction
可以使用系统定义好的,也可以自定义
可以使用 setAction() 或 Intent 构造函数为 Intent 指定操作
数据 mData
待操作数据或者数据的类型等信息
要仅设置数据 URI,请调用 setData()
要仅设置 MIME 类型,请调用 setType()
如果同时设置以上两点,就使用 setDataAndType() 同时显式设置二者
类别 mCategories
表示 Intent 属于哪个类别
一个 Intent 可以属于多个类别,如果不声明,就属于默认的类别 default
可以使用 addCategory() 指定类别
附加数据 mExtras
Intent 可以携带完成请求操作所需的数据,格式为键值对
可以使用各种 putExtra() 方法添加数据
也可以创建一个包含所有数据的 Bundle 对象,然后使用 putExtras() 将Bundle 插入 Intent 中
标志位 mFlags
标志位可以指示 Android 系统如何启动 Activity 以及启动之后如何处理
可以使用 addFlags() 方法添加标志位
注:
1.启动 Service 时应该始终指定组件名称。 否则无法确定哪项服务会响应 Intent,且用户无法看到哪项服务已启动。
2.若要同时设置 URI 和 MIME 类型,请勿调用 setData() 和 setType(),因为它们会互相抵消彼此的值。
3.Intent 类将为标准化的数据类型指定多个 EXTRA_* 常量。例如,使用 ACTION_SEND 创建用于发送电子邮件的 Intent 时,可以使用 EXTRA_EMAIL 键指定“目标”收件人,并使用 EXTRA_SUBJECT 键指定“主题”。
Intent 的类型
Intent 分为两种类型:
显式 Intent
隐式 Intent
显式 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);
1
2
3
4
5
6
上述代码构建了一个 Intent,然后为它设置了 action, data 和 extra 数据,然后调用了 startActivity()。
接着系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(在这里即:含 ACTION_SENDTO 操作并携带短信数据的 Intent ):
如果只有一个应用能够处理,则该应用将立即打开并为其提供 Intent
如果多个 Activity 接受 Intent,则系统将显示一个对话框,使用户能够选取要使用的应用
而在检查每个 Activity 能否处理 Intent 的过程中,需要访问 Intent 过滤器(IntentFilter)。
Intent 过滤器 IntentFilter
我们可以在 AndroidManifest.xml 中给 Activity 设置一个 IntentFilter 属性,比如这样:
android:alwaysRetainTaskState="true"
android:label="singleTask"
android:launchMode="singleTask"
android:taskAffinity="top.shixinzhang.task2">
1
2
3
4
5
6
7
8
9
10
11
12
IntentFilter 中可以设置 action, category 和 data 三种过滤信息,每一种信息都可以有多个。
一个 Activity 也可以有多个 IntentFilter,相当于多了几个过滤器,被筛选到的可能就更大了。
android:alwaysRetainTaskState="true"
android:label="singleTask"
android:launchMode="singleTask"
android:taskAffinity="top.shixinzhang.task2">
android:host="myapp.mycompany.com"
android:scheme="myapp"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
上面的代码为该 Activity 多增加了一个过滤器,这使得在加载特定 URI 时,它可以被当做浏览器使用。
我们将分别介绍三种过滤信息的匹配规则。
IntentFilter 的匹配规则
1.action 的匹配规则
action 可以理解为一个组件具备功能、可以进行什么操作。系统为我们提供了很多内置的 action,当然也可以自定义。
一个 Intent-filter 中可以有多个 action,就好比一个人有多种才能。
...
1
2
3
4
5
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
2.category 的匹配规则
category 即分类,和 action 一样,一个过滤器可以包含多个分类:
...
1
2
3
4
5
和 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):
3.data 的匹配规则
data 表示该组件可以支持的数据格式与类型。
同样,一个过滤器也可以有多个 data:
...
1
2
3
4
5
一个 data 由两部分组成:
mimeType
scheme
mimeType 指的是支持的数据类型与格式,常见的有:
text/plain
image/jpeg
video/*
audio/*
/ 号前面的是数据类型,后面是具体格式。
scheme 就是常见的 URI 格式:
1
具体部分介绍及重要性如下:
scheme: 协议类型
最重要,协议类型决定了如何访问数据,比如是本地还是网络
host: 主机
第二重要,主机地址决定了具体 ip
port:端口
第三重要,一个主机可能有多个网卡端口,有了端口后才能访问到具体
path:具体路径
最后一级,表示要访问的文件夹路径
比如:
http://www.baidu.com:80/search/info
file://emulator/0/sdcard/shixinzhang
1
2
在 intent-filter 中,声明 scheme 必须从前往后,逐步缩小范围。
你可以只声明一个协议,这表示该协议下的所有数据你都可以处理;同样也可以只声明主机地址,这表示使用该协议,访问该主机下的所有数据你都可以处理。
scheme 和 mimeType 组成一个 data。而 data 的匹配规则就是:intent 中的 data 至少可以匹配过滤器中的一个。
也就是说:
如果 intent-filter 只声明了 scheme,那你的 intent 中必须只包含 scheme 并且至少和 intent-filter 中的一个 scheme 匹配才可以
如果 intent-filter 只声明了 mimeType,那你的 intent 中除了 type 要和 intent-filter 一致,还需要额外包含 content 或者 file 的 scheme 才行,因为 intent-filter 默认包含这两个 scheme
如果 intent-filter 同时声明了多个 scheme 和 mimeType,那你的 intent 至少要完全匹配其中的一组
注意 intent-filter 默认的 content 或者 file 的 scheme ,它表示默认组件能够从文件中或内容提供程序获得本地数据。
比如下面的 intent-filter,它表示该组件可以从内容提供商处获得并显示图像数据:
...
1
2
3
4
另一常见的配置是 scheme 只声明协议,同时声明数据类型的过滤器。
例如,下文中的 元素向 Android 指出,组件可从网络中检索视频数据以执行操作:
...
1
2
3
4
5
总结过滤规则
如果把组件比作一个安卓程序员,我们需要三个条件来筛选出我们想要的那位:
擅长什么开发,UI、网络、音视频? (对应 action)
至少具备要求中的一条才可以
是哪类程序员,求知欲强、自我驱动?(对应 category )
必须和要求完全一致才可以
使用什么工具开发,AS、Eclipse、记事本?(对应 data)
至少具备要求中的一条才可以
注意
如果当前设备中没有能够匹配你发送到 startActivity() 的隐式 Intent,则调用将会失败,且应用会崩溃。
因此我们需要对 Intent 对象调用 resolveActivity():
如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用 startActivity()
如果结果为空,则不应使用该 Intent
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);
}
---------------------
作者:拭心
来源:CSDN
原文:https://blog.csdn.net/u011240877/article/details/71305797