隐式意图和intentFilter匹配
2015-12-24 09:37
507 查看
隐式意图
隐式意图:在程序中没有为Intent对象的
mComponent属性明确指出想要其启动组件。
隐式意图仅仅是为
Intent对象指出一些筛选条件,然后
Android系统会取出
Intent对象中的数据和所有已经注册到系统中的组件进行匹配。
- 若匹配成功,则系统将激活该组件。 - 若有多个组件匹配成功,则系统将弹出一个对话框,要求用户选择所要激活的组件。 - 若没有任何组件匹配成功则抛异常。
应用程序中定义的
Android组件都需要在
AndroidManifest.xml文件中记录。当系统在进行意图匹配时,就会取出
Intent对象中的筛选条件与所有已注册到系统中的各个组件的
<intent-filter>标签下定义的数据进行匹配。
上面所说的“筛选条件”指的就是
Intent对象以下三个方面:
1、动作(mAction) 2、数据(mData和mType) 3、分类(mCategories)
也就是说,我们通过为Intent的上面四个属性赋值,来执行“设置筛选条件”,然后操作系统也会读取这四个属性,并用它们进行匹配。
动作
mAction:是
String类型的,用来告诉系统本次请求要执行什么样的动作。如:张三看书、李四唱歌中的
“看”、
“唱”就是指动作。在Android中内置的动作有很多,常见的有:
- Intent.ACTION_VIEW :“查看”动作。 - Intent.ACTION_EDIT :“编辑”动作。 - Intent.ACTION_DELETE :“删除”动作。 - Intent.ACTION_CALL:“呼叫”动作,通常指打电话。 - Intent.ACTION_MAIN :标记当前Activity是程序的入口。
数据
数据:
“动作”所要操作的数据,显然不同的动作要跟不同的数据规范类型配合使用,比如:
- 如果动作是ACTION_VIEW,那么数据就应该指向一个可被查看的东西,比如网页、图片、视频等。 - 如果动作字段是ACTION_EDIT,那么它的数据应该指向它所要编辑的数据。 - 如果动作是ACTION_CALL,那么数据就应该是一个呼叫号码。
再具体点说,数据包括两部分:
mData和
mType:
- 数据的URI(mData):用来指出数据所在的位置。如file:///tmp/android.txt。 - 数据的类型(mType):用来指出数据的MIME类型。如:text/html 。
分类
mCategories:
“动作”的附加信息(可以有多个)。在Android中内置的类型有:
- Intent.CATEGORY_LAUNCHER :目标Activity能够被列在应用程序启动器上。 - Intent.CATEGORY_BROWSABLE :目标Activity能够安全的调用浏览器来显示链接所指向的数据(如图片或电子邮件)。 - Intent.CATEGORY_HOME :目标Activity显示在主屏幕上。
IntentFilter类
通过前面的介绍,我们已经知道这三点:- 创建完Activity等组件后,还需要在清单文件中配置它们,以便让系统知道这些组件的存在。 - 在配置它们的时候,除了ContentProvider之外的另外三个组件都可以配置一个或多个<IntentFilter>,它表示过滤器。 - 当我们需要启动一个组件时,整个流程是这样的: - 首先,我们创建一个Intent对象,然后将它传递给操作系统。 - 然后,系统会检测Intent,若它是显式意图的直接启动目标组件,否则会依据Intent内部的信息进行匹配。 - 接着,如果我们调用的startActivity来启动组件,那么系统会获取当前所有注册到系统中的Activity,并获取它们的<IntentFilter>。 - 最后,让Intent对象和这些Activity的<IntentFilter>进行匹配,匹配成功就会启动该Activity,若有多个Activity都匹配成功,则系统会让用户选择启动哪一个。 - 另外,组件可以有多个<IntentFilter>标签,只要该组件有一个匹配成功,则就能启动。
IntentFilter类与
<IntentFilter>标签对应,它有类似于Intent对象的动作、数据、和分类字段。
Action匹配
在清单文件中的
<intent-filter>元素内的
<action>子元素对应咱们前面说的“动作”。如:
12345 | <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> |
语句解释: - 像本例显示的这样,一个过滤器可以列出多个Action。但这个列表不能是空的,一个过滤器必须包含至少一个<action>元素,否则它不会匹配任何Intent对象。 - 要通过这个检测,在Intent对象中指定的Action必须跟这个过滤器的动作列表中的某个Action一致匹配。
进行意图匹配时,只有在Intent的
mAction属性与
<intent-filter>下的某个
<action>标签的值匹配成功后,才会去匹配
mCategories属性。
Category检测
<intent-filter>元素内的
<category>子元素对应前面说的“分类”。例如:
1234 | <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /></intent-filter> |
Category检测的
Intent对象,在
Intent对象中所包含的每个分类,过滤器中都必须得包含,过滤器能够列出Intent中不包含的分类,但是它不能忽略
Intent对象中的任何分类。
因此,原则上一个没有
category的
Intent对象应该始终通过这个检测,而不管过滤器中声明的分类。
注意:
- 所有传递给startActivity()方法的隐式Intent对象,都会至少包含了一个android.intent.category.DEFAULT。 - 只有Intent对象的mCategorie里的所有类型都匹配成功后,才会去匹配<data>标签。
Data检测
像
Action、
Category检测一样,针对
IntentFilter的“数据”也要包含在一个子元素中,这个子元素能够出现
0~n次。例如:
1234 | <intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" /> <data android:mimeType="audio/mpeg" android:scheme="http" /></intent-filter> |
<data>元素能够指定
URI和数据类型(
MIME)对于每个
URI部分都会有独立的属性:scheme、host、port、path。格式:
1 | <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>] |
1 | content://com.example.project:200/folder/subfolder/etc |
- scheme是content - host 是com.example.project - port 是200 - path 是folder/subfolder/etc。
其中
host和
port一起构成了
authority,如果没有指定
host,那么
port也会被忽略。
开始匹配
范例1:新建Activity。123456 | <activity android:name="org.cxy.intent.SecondActivity"> <intent-filter> <action android:name="act.second"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter></activity> |
123 | Intent intent = new Intent();intent.setAction("act.second"); this.startActivity(intent); |
语句解释: - 本范例并没有为Intent指定具体要跳转到哪个Activity,而是为Intent指定一个action。 - 在调用startActivity方法启动Activity时,该方法会自动为Intent对象设置一个category,即:“android.intent.category.DEFAULT”。
范例2:data匹配。
1234567 | <activity android:name="org.cxy.intent.SecondActivity"> <intent-filter> <action android:name="org.cxy.action.Second"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http" android:host="www.cxy.com" android:port="80" android:path="/hi.jsp"/> </intent-filter></activity> |
1234 | Intent intent = new Intent();intent.setAction("org.cxy.action.Second");intent.setData(Uri.parse("http://www.cxy.com:80/hi.jsp"));this.startActivity(intent); |
语句解释: - 使用scheme属性匹配代码中的协议名。 - 使用host属性匹配代码中的主机名,使用此属性之前,必须要先指定scheme属性,在代码中scheme和host之间要写上“://”作为间隔。 - 使用port属性匹配代码中的端口号,使用path属性匹配代码中的路径。
范例3:数据类型匹配。
12345678 | <activity android:name="org.cxy.intent.SecondActivity"> <intent-filter> <action android:name="org.cxy.action.Second"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http" android:host="www.cxy.com" android:port="80" android:path="/hi.jsp" android:mimeType="image/gif"/> </intent-filter></activity> |
1234 | Intent intent = new Intent();intent.setAction("org.cxy.action.Second");intent.setDataAndType(Uri.parse("http://www.cxy.com:80/hi.jsp"),"image/gif");this.startActivity(intent); |
语句解释: - 使用mimeType属性可以对数据的MIME类型进行限制。 - 使用setData方法设置Intent的Uri,使用setType方法设置Intent的MIME类型。 - 但是如果你想同时设置这两者,则只能使用setDataAndType方法,因为setData和setType方法中会彼此清除对方的值,具体请查看源码。
在
<intent-filter>中可以不列出
<data>元素,但是只要列出了,那么
<data>中所列出的所有属性都得匹配。
范例4:假设我们有如下配置:
1234567 | <activity android:name=".B"> <intent-filter> <action android:name="aa.test.BBBBBB"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="image/*"/> </intent-filter></activity> |
1234 | Intent intent = new Intent();intent.setAction("aa.test.BBBBBB");intent.setDataAndType(Uri.parse("content://abc"),"image/png");startActivity(intent); |
语句解释: - 也就是说,虽然我们没有为<data>元素设置scheme属性,但是它却存在默认值,会默认匹配“file”、“content”。 - 另外,在<data>元素的path和mimeType属性的值中,都可以包含通配符“*”,用来匹配0~n个任意字符。
范例5:安装应用程序。
1234 | Intent intent = new Intent(Intent.ACTION_VIEW);// Uri.fromFile()方法根据文件对象的路径来构造一个Uri。intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");startActivity(intent); |
语句解释: - 本范例使用系统内置的ACTION_VIEW动作安装APK文件。 - ACTION_VIEW动作所要操作的数据的Uri是通过一个File对象的路径构造出来的。 - ACTION_VIEW动作用于“查看”,该动作会根据其所要查看的数据的MIME类型的不同,来调用不同的应用程序来查看数据。 - APK文件的MIME类型为application/vnd.android.package-archive ,而查看APK文件,其实就是安装APK文件。
范例6:卸载应用程序。
1234 | Intent intent = new Intent();intent.setAction(Intent.ACTION_DELETE);intent.setData(Uri.parse("package:"+ this.getPackageName()));startActivity(intent); |
语句解释: - 调用系统内置的ACTION_DELETE动作可以执行删除操作。 - 若删除的数据为:“package:应用程序包名”,则相当于卸载该应用程序。 - 调用Activity的getPackageName()方法可以获取当前应用程序的包名称。
范例7:启动发送短信Acitivity。
12345678 | Intent intent = new Intent();// 设置意图的动作为“发送”和“发送数据”的MIME类型。intent.setAction(Intent.ACTION_SEND);intent.setType("text/plain"); // 设置要发送的 正文数据。intent.putExtra(Intent.EXTRA_TEXT, "Hi 发送短信哦!");startActivity(intent); |
语句解释: - 程序运行时会打开系统发送短信界面。
扩展:
当我们使用隐式意图启动一个A时,可以做一下判断,看是否有A能够匹配我们的隐式意图,如果不判断就有可能因找不到而报错。
所以我们采用:
PackageManager类中有一组
query…()以及
resolve…()方法。
前者返回能够接受一个特殊
Intent对象的所有组件,后者返回最佳匹配结果(即只返回1个结果),例如:
- queryIntentActivities(Intent intent,int flags)方法返回能够执行这个Intent对象的所有Activity。
第二个参数我们使用:MATCH_DEFAULT_ONLY 这个表示仅仅匹配那些intent-filter中声明的
<category android:name="android.intent.category.DEFAULT"/>的Activity。因为不含有Default的那些Activity是无法接受隐式意图。 - queryIntentServices()方法类似地返回Service列表。 - queryBroadcastReceivers()方法类似地返回Broadcast Receiver列表。
这些方法都不激活组件,它们只是列出能够响应这个
Intent对象的所有组件。
相关文章推荐
- springboot错误处理页面
- DirectShow 播放mp4编码 视频
- Handler&内部类导致的内存泄露问题
- AndroidStudio怎样导入jar包
- C#隐藏控制台窗体
- vc++比较三个数的大小
- JavaScript一些关键概念
- String to Date 多种格式转换
- matlab sum和cumsum函数
- 怎样使用Ipad远程控制你的电脑
- 在DVR中增加UTC-CGI接口
- “CreateRiaClientFilesTask”任务意外失败。 未能加载文件程序集“System.ComponentModel.DataAnnot...
- STL map
- android开发动画使用初识
- 【c/c++】delete和delete[]详解
- <小知识总结>
- (转)属性与特性
- socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto
- Linux系统CentOS安装在VMware上却连不了外网的解决方案
- 分类算法总结