Android中隐式Intent的用途 -- 基础知识
对于明确指出了目标组件名称的Intent,我们称之为“显式Intent”。对于没有明确指出目标组件名称的Intent,则称之为“隐式Intent”。Android系统使用Intent Filter 来寻找与隐式Intent相关的对象.
隐式Intent往往用于不同应用程序之间的使用。由于开发人员往往并不清楚别的应用程序的组件名称,因此,隐式Intent便尤为重要。
对于隐式Intent,由于没有明确的目标组件名称,所以必须由Android系统帮助应用程序寻找与Intent请求意图最匹配的组件。具体的选择方法是:Android将Intent的请求内容和一个叫做intent-filter比较,Intent Filter中包含系统中所有可能的待选组件。如果Intent Filter中某一组件匹配隐式Intent请求的内容,那么Android就选择该组件作为该隐式Intent的目标组件.
Android 如何知道应用程序能够处理某种类型的Intent 请求呢?这需要应用程序在AndroidManifest.xml中声明自己所含组件的过滤器(即可以匹配哪些Intent请求)。一个没有声明Intent Filter的组件只能响应指明自己名字的显式Intent请求,而无法响应隐式Intent请求。在配置文件中,常见的intent-filter声明如下:
<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="com.android.notes.action.EDIT_NOTE" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
而一个声明了intent-filter的组件既可以响应显式Intent请求,也可以响应隐式Intent请求。在通过和intent-filter比较来解析隐式Intent请求时,Android将以下三个因素作为选择的参考标准。
Action
Data
Category
而Entra和Flag在解析收到Intent时是并不起作用的。
Intent Filter
应用程序的组件为了告诉Android自己能响应、处理哪些隐式Intent请求,可以声明一个甚至多个intent-filter。每个Intent Filter描述该组件所能响应Intent请求的能力——组件希望接收什么类型的请求行为,什么类型的请求数据。
如何为组件声明自己的IntentFilter? 常见的方法是在AndroidManifest.xml文件中用属性<Intent-Filter>描述组件的Intent Filter。
前面我们提到,隐式Intent和IntentFilter进行比较时的三要素是Intent的动作、数据以及类别。实际上,一个隐式Intent请求要能够传递给目标组件,必要通过这三个方面的检查。如果任何一方面不匹配,Android都不会将该隐式Intent传递给目标组件。接下来我们讲解这三方面检查的具体规则。
1.动作测试
<intent-filter>元素中可以包括子元素<action>,比如:
<intent-filter>
<actionandroid:name="com.example.project.SHOW_CURRENT" />
<actionandroid:name="com.example.project.SHOW_RECENT" />
<actionandroid:name="com.example.project.SHOW_PENDING" />
</intent-filter>
一条<intent-filter>元素至少应该包含一个<action>,否则任何Intent请求都不能和该<intent-filter>匹配。
如果Intent请求的Action和<intent-filter>中个某一条<action>匹配,那么该Intent就通过了这条<intent-filter>的动作测试。
如果Intent请求或<intent-filter>中没有说明具体的Action类型,那么会出现下面两种情况。
(1) 如果<intent-filter>中没有包含任何Action类型,那么无论什么Intent请求都无法和这条<intent-filter>匹配;
(2) 反之,如果Intent请求中没有设定Action类型,那么只要<intent-filter>中包含有Action类型,这个Intent请求就将顺利地通过<intent-filter>的行为测试。
2.类别测试
<intent-filter>元素可以包含<category>子元素,比如:
<intent-filter. . . >
<categoryandroid:name="android.Intent.Category.DEFAULT" />
<categoryandroid:name="android.Intent.Category.BROWSABLE" />
</intent-filter>
只有当Intent请求中所有的Category与组件中某一个Intent-filter的<category>完全匹配时,才会让该Intent请求通过测试,Intent-filter中多余的<category>声明并不会导致匹配失败。
android.intent.category.DEFAULT的作用
每一个通过 startActivity()方法发出的隐式 Intent 都至少有一个 category,就是 "android.intent.category.DEFAULT",所以只要是想接收一个隐式Intent 的 Activity 都应该包括 "android.intent.category.DEFAULT" category,不然将导致 Intent匹配失败。
3.数据测试
数据在<intent-filter>中的描述如下:
<intent-filter. . . >
<data android:type="video/mpeg" android:scheme="http" . . . />
<data android:type="audio/mpeg" android:scheme="http" . . . />
</intent-filter>
<data>元素指定了希望接受的Intent请求的数据URI和数据类型,URI被分成三部分来进行匹配:scheme、authority和path。其中,用setData()设定的Intent请求的URI数据类型和scheme必须与Intent-filter中所指定的一致。若Intent-filter中还指定了authority或path,它们也需要相匹配才会通过测试。
每个数据<data>元素可以指定一个URI和一个数据类型(MIME媒体类型)。有一些单独的属性-模式,主机,端口和路径-URI的每个部分:
scheme://host:port/path
content://com.example.project:200/folder/subfolder/etc
模式是"内容",主机是"com.example.project",端口是"200",路经是"folder/subfolder/etc"。主机和端口一起组成URI鉴权(authority);如果未指定主机,端口会被忽略。
这些属性都是可选的,但彼此有依赖关系:一个授权要有意义,必须指定一个模式。一个路经要有意义,必须同时指定模式和鉴权。
当一个意图对象中的URI被用来和一个过滤器中的URI规格比较时,它实际上比较的是上面提到的URI的各个部分。比如,如果过滤器仅指定了一个模式,所有那个模式的URIs和这个过滤器相匹配;如果过滤器指定了一个模式、鉴权但没有路经,所有相同模式和鉴权的URIs可以匹配上,而不管它们的路经;如果过滤器指定了一个模式、鉴权和路经,只有相同模式、鉴权和路经的URIs可以匹配上。当然,一个过滤器中的路径规格可以包含通配符,这样只需要部分匹配即可。
数据<data>元素的类型属性指定了数据的MIME类型。这在过滤器里比在URI里更为常见。意图对象和过滤器都可以使用一个"*"通配符指定子类型字段-比如,"text/*"或者"audio/*"-指示任何匹配的子类型。
数据测试同时比较意图对象和过滤器中指定的URI和数据类型。规则如下:
a. 一个既不包含URI也不包含数据类型的意图对象仅在过滤器也同样没有指定任何URIs和数据类型的情况下才能通过测试。
b .一个包含URI但没有数据类型的意图对象仅在它的URI和一个同样没有指定数据类型的过滤器里的URI匹配时才能通过测试。这通常发生在类似于mailto:和tel:这样的URIs上:它们并不引用实际数据。
c. 一个包含数据类型但不包含URI的意图对象仅在这个Intent-filter列举了同样的数据类型而且也没有指定一个URI的情况下才能通过测试。
d. 一个同时包含URI和数据类型(或者可从URI推断出数据类型)的意图对象可以通过测试,如果它的类型和过滤器中列举的类型相匹配的话。如果它的URI和这个过滤器中的一个URI相匹配或者它有一个内容content:或者文件file: URI而且这个过滤器没有指定一个URI,那么它也能通过测试。换句话说,一个组件被假定为支持content:和file: 数据如果它的过滤器仅列举了一个数据类型。(这个是网上copy过来,)
PS:如果一个意图可以通过不止一个活动或服务的过滤器,用户可能会被询问要激活那个组件。这个倒是经常遇到。例如,当你手机上安装多个浏览器的时候,调用浏览器,回弹出对话框,询问你到底启动哪一个应用。如果没有发现目标对象将会出现异常。