Android中隐式Intent的用途(1) -- 基础知识

时间:2022-11-05 15:31:57
 scheme filter 测试 浏览器

                       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:如果一个意图可以通过不止一个活动或服务的过滤器,用户可能会被询问要激活那个组件。这个倒是经常遇到。例如,当你手机上安装多个浏览器的时候,调用浏览器,回弹出对话框,询问你到底启动哪一个应用。如果没有发现目标对象将会出现异常。