注意:本篇文章是本人阅读相关文章所写下的总结,方便以后查阅,所有内容非原创,侵权删。
本篇文章内容来自于:
你必须弄懂的Intent Filter匹配规则
史上最全intent-filter匹配规则,没有之一
目录
- 什么是Intent Filter(intentFilter+data+category)
- action的匹配规则/setAction
- data的匹配规则(uri+mimetype)/setData、setType、setDataAndType
- category的匹配规则 addCategory
- Extra
--5.1 intent-filter匹配优先级
--5.2 查询是否有Activity可以匹配我们指定Intent的组件
1. 什么是Intent Filter
Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。
在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行匹配判断的,只有完全匹配才能启动Activity。
若声明了多个Intent Filter,只需要匹配任意一个即可启动该组件。
<activity
android:name="com.saiermeng.intent.SecondActivity"
android:label="@string/title_activity_second">
<intent-filter>
<action android:name="com.saiermeng.intent.open02" />
<data
android:host="www.saiermeng.com"
android:path="/java"
android:port="8080"
android:scheme="http"></data>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
2. action的匹配规则
action是一个字符串。
如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配。
可通过setAction方法为Intent设置action,也可在构造Intent时传入action。
需要注意的是,隐式Intent必须指定action。
一个Intent Filter中可声明多个action,Intent中的action与其中的任一个action在字符串形式上完全相同(注意,区分大小写,大小写不同但字符串内容相同也会造成匹配失败),action方面就匹配成功。
比如:
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_TO"/>
</intent-filter>
//那么只要Intent的action为“SEND”或“SEND_TO”,那么这个Intent在action方面就能和上面那个Activity匹配成功。
Intent intent = new Intent("android.intent.action.SEND") ;
Android系统预定义了许多action,这些action代表了一些常见的操作。常见action如下(Intent类中的常量):
Intent.ACTION_VIEW
Intent.ACTION_DIAL
Intent.ACTION_SENDTO
Intent.ACTION_SEND
Intent.ACTION_WEB_SEARCH
3. data的匹配规则
如果Intent没有提供type,系统将从data中得到数据类型。
只要Intent的data只要与Intent Filter中的任一个data声明完全相同,data方面就完全匹配成功。
data由两部分组成:mimeType和URI
MineType指的是媒体类型:例如image/jpeg,auto/mpeg4和viedo/*等,可以表示图片、文本、视频等不同的媒体格式
常用的文件的mine type类型
URI格式如下
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern >]
//比如
content://com.wooyun.org:200/folder/etc
http://www.wooyun.org/search/info
Intent的uri可通过setData方法设置,mimetype可通过setType方法设置。
若Intent Filter的data声明部分未指定uri,则缺省uri为content或file,Intent中的uri的scheme部分需为content或file才能匹配;
若要为Intent指定完整的data,必须用setDataAndType方法。
因为setData和setType方法的源码中会彼此互相清除对方的值,即setData会把mimeType置为null,setType会把uri置为null。
<data
//scheme:整个URI的模式,如常见的http,file等
//注意如果URI中没有指定的scheme,那么整个uri无效
android:scheme="String"
//host:URI的域名,比如我们常见的www.mi.com、www.baidu.com
//与scheme一样,一旦没有host那么整个URI也毫无意义;
android:host="String"
//port:端口号,比如80
//只有在URI中指定了scheme和host之后端口号才是有意义的;
android:port="String"
//path:表示完整的路径
android:path="String"
//pathPattern在path基础上可以包含通配符
android:pathPattern="String"
//pathPrefix:表示路径的前缀信息
android:pathPrefix="String"
//MineType指的是媒体类型:例如image/jpeg,auto/mpeg4和viedo/*等,可以表示图片、文本、视频等不同的媒体格式
android:mimeType="String"/>
path、pathPrefix、pathPattern 之间的区别
比如http://example.com/blog/abc.html
path用来匹配完整的路径,这里将 path 设置为 /blog/abc.html 才能够进行匹配;
pathPrefix 用来匹配路径的开头部分,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
pathPattern 用表达式来匹配整个路径
关于表达式中的匹配符号与转义
匹配符号:
“” 用来匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”…
“.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”…
因此 “.” 就是用来匹配任意字符0次或更多,如:“.html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”…
转义:因为当读取 Xml 的时候,“/” 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:“” 这个字符就应该写成 “//”,“/” 这个字符就应该写成 “////”。
使用案例:
//案例一:打开pdf文件显示自己的应用
//匹配 http 以 “.pdf” 结尾的路径
//使得别的程序想要打开网络 pdf 时,用户能够可以选择我们的程序进行下载查看。
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="http" android:pathPattern=".*//.pdf"></data>
</intent-filter>
//案例二:使用户转发信息时显示自己的应用
//如果我们做的是一个IM应用,或是其他类似于微博之类的应用
//让别人转发信息时通过 Intent 进行调用时出现在选择框里
//我们只用注册 android.intent.action.SEND 与 mimeType 为 “text/plain” 或 “/” 就可以了
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data mimeType="*/*" />
</intent-filter>
//案例三:当用户打开音乐文件出现我们的应用
//如果我们做的是一个音乐播放软件,当文件浏览器打开某音乐文件的时候,使我们的应用能够出现在选择框里。
//我们只用注册 android.intent.action.VIEW 与 mimeType 为 “audio/*” 就可以了
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="audio/*" />
</intent-filter>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
区别一:
android.intent.action.MAIN决定一个应用程序最先启动那个组件
android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里(说白了就是是否在桌面上显示一个图标)
这两个属性组合情况:
第一种情况:有MAIN,无LAUNCHER,程序列表中无图标
原因:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
第二种情况:无MAIN,有LAUNCHER,程序列表中无图标
原因:android.intent.action.MAIN决定应用程序最先启动的Activity,如果没有Main,则不知启动哪个Activity,故也不会有图标出现
所以这两个属性一般成对出现。
如果一个应用中有两个组件intent-filter都添加了android.intent.action.MAIN和
android.intent.category.LAUNCHER这两个属性, 则这个应用将会显示两个图标, 写在前面的组件先运行。
区别二:
android.intent.category.LAUNCHER:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里,就是android开机后的主程序列表。
android.intent.category.HOME:按住“HOME”键,该程序显示在HOME列表里。
4. category的匹配规则
category也是一个字符串。
它要求Intent中如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中的定义了的category。
当然,Intent中也可以没有category(若Intent中未指定category,系统会自动为它带上“android.intent.category.DEFAULT”),如果没有,仍然可以匹配成功。
category和action的区别在于,
action要求Intent中必须有一个action且必须和过滤规则中的某几个action相同,
而category要求Intent可以没有category,但是一旦发现存在category,不论你有多少,每个都要能够和过滤规则中的任何一个category相同。
我们可以通过addCategory方法为Intent添加category。
每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent 匹配失败.
5. Extra
5.1 intent-filter匹配优先级
首先查看Intent的过滤器(intent-filter),按照以下优先关系查找:action->data->category
参考链接:http://blog.csdn.net/cnnumen/article/details/8464786
5.2 查询是否有Activity可以匹配我们指定Intent的组件
采用PackageManager的resolveActivity或者Intent的resolveActivity方法会获得最适合Intent的一个Activity
调用PackageManager的queryIntentActivities会返回所有成功匹配Intent的Activity
应用:杜绝异常的发生
如果intent匹配不到,会抛出异常。
为了避免发生以上异常,我们可以使用PackageManager或者Intent的resolveActivity()方法,如果intent和过滤规则匹配失败,那么将返回null,我们也就不会再继续调用startActivity方法啦,从而去修改intent再次进行匹配直到成功匹配到预期intent。