Intent-Filter匹配规则

本文详细阐述了Android中Intent-Filter的匹配规则,包括action、category、data三方面的具体匹配逻辑,并介绍了如何查询可接收指定Intent的Activity。

Intent-Filter匹配规则

    只有action、data、category三方都匹配,Intent才算是匹配成功,进而才能启动相应的Activity。一个Activity若声明了多个 Intent-Filter,只需要匹配任意一个即可启动该Activity。

 

(1)action的匹配规则

    action 是一个字符串,系统预定义了一些 action,同时我们也可以在应用中定义自己的 action。action 的匹配规则是 Intent 中的 action 必须能够和 Intent-Filter中的action 匹配(action 的字符串值完全一样,action 字符串区分大小写), 一个 Intent-Filter 中可声明多个action,Intent 中的 action 与其中的任一个 action 在字符串形式上完全相同即可匹配成功。

 

   需要注意的是,隐式Intent必须指定action(如不指定action则必须指定data或mimetype。这种情况下,只要Intent-Filter 至少含有一个action就可以匹配),如果没有指定,则匹配失败。比如我们在Manifest文件中为MyActivity定义了如下 Intent-Filter:

<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 intent = new Intent("android.intent.action.SEND")

(2)category的匹配规则

    category 是一个字符串,系统预定义了一些category ,同时我们也可以在应用中定义自己的category 。

    与action不同,Intent 中的 category 必须都在 Intent-Filter中出现才算匹配成功。Intent可以不指定category,若Intent中未指定category,系统在调用 startActivity 或者 startActivityForResult 时,会默认为 Intent 加上“android.intent.category.DEFAULT”这个 category 。所以为了我们的 activity 能够被隐式调用,就必须在manifest文件中的 Intent-Filter 声明中带上“android.intent.category.DEFAULT”。我们可以通过 intent.addCategory方法为Intent添加category。

 

(3)data的匹配规则

    data 的匹配规则和 action 类似,如果 Intent-Filter中定义了 data,则 Intent 中必须也要定义可匹配的 data。data 的语法如下所示:

<data android:scheme="String"
      android:host="String"
      android:port="String"
      android:path="String"
      android:pathPrefix="String"
      android:pathPattern="String"
      android:mimeType="String"/>

 

    data 由 mimeType 和 URI 两部分组成。

    mimeType 指定媒体类型,如 image/jepeg、audio/mpeg4-generic、video/* 等,可以表示图片、文本、视频等不同的媒体格式。

    URI 的结构如下:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

   比如下面的两个URI

content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info

scheme:URI 的模式,比如http、file、content 等,如果URI 中没有指定 scheme,则整个URI 的其他参数无效,URI 无效

host:URI 的主机名,比如 www.baidu.com ,如果host  未指定,则整个URI 的其他参数无效,URI 无效

port:URI 中的端口号,比如 80,仅当 URI 中指定了 scheme 和 host 参数的时候,port 参数才有意义

path、pathPrefix、pathPattern:表述路径信息,其中 path 表示完整的路径信息,pathPattern 也表示完整的路径信息,但它里面可以包含通配符 “*”,“*” 表示0个或多个任意字符,由于正则表达式的规范,如果想标示真实的字符串,“*” 要改写成“\\*”,“\” 要改写成“\\\”;pathPrefix 表示路径的前缀信息。

    Intent的 uri 可通过 setData 方法设置,mimetype 可通过 setType 方法设置。隐式 Intent 也必须指定 data。同 action类似,只要 Intent 的 data 只要与 Intent-Filter中的任一个 data 声明完全相同,data 方面就匹配成功。

<intent-filter>
    <data android:mimeType="image/*"/>
</intent-filter>

     这种规则指定了 媒体类型为所有类型的图片,则 Intent 中的 mimeType 属性必须为 “image/*” 才能匹配,需要注意的是若 Intent-Filter的 data 声明部分未指定 uri,则缺省 uri 为 content 或 file,Intent 中的 uri 的 scheme 部分需为 content或file才能匹配;

intent.staDataAndType(Uri.parse("file:abc"),"image/png")

    若要为 Intent 指定完整的 data,必须用 setDataAndType 方法,不能先调用 setData 再调用 setType,因为这两个方法彼此会清楚对方的值,源码如下:

    setData源码:

public Intent setData(Uri data) {
    mData = data;
    mType = null;
    return this;
}

   setType源码:

public Intent setType(String type) {
    mData = null;
    mType = type;
    return this;
}

    从以上代码可以看到,setData会把mimeType置为null,setType会把uri置为null。下面我们来举例说明一下data的匹配。

    在data 语法中,scheme、host等各个部分无需全部指定。假如我们为MyActivity的 Intent-Filter 指定了如下data:

<intent-filter>
    <data android:mimeType="vidoe/mpeg" android:scheme="http" android:host="www.xxx.com" />
    <data android:mimeType="text/plain" android:scheme="http" />
</intent-filter>

    那么我们的Intent想要匹配,mimeType可以为”text/plain"或“video/mpeg",scheme必须为”http“,host则没有限制,因为第二个data没有指定host。

intent.staDataAndType(Uri.parse("http:www.xxx.com"),"vidoe/mpeg")
intent.staDataAndType(Uri.parse("http:abc"),"text/plain")

    data 有两种特殊的写法,它们的作用是一样的,如下所示:

<intent-filter>
    <data android:host="www.baidu.com"
          android:scheme="file"/>
</intent-filter>

<intent-filter>
    <data android:scheme="file"/>
    <data android:host="www.baidu.com"/>
</intent-filter>

 

(4)查询是否有可接收指定 Intent 的 Activity

    当我们通过隐式方式启动一个 Activity 时,可做一下判断,看是否有Activity 能够匹配我们的隐式 Intent,如果不做判断,有可能出现找不到 Activity 的异常。

    采用 PackageManager 的resolveActivity 或者 Intent 的 resolveActivity 方法会获得最适合Intent的一个Activity,如果找不到匹配的 Activity 就会返回null , 我们通过判断返回值就可避免出现找不到 Activity 的异常,PackageManager 还提供了 queryIntentActivities 方法查找所有成功匹配 Intent 的 Activity。

    queryIntentActivities 和 resolveActivity 方法原型:

public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
            @ResolveInfoFlags int flags);

public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);

    上述两个方法的第一个参数就是Intent,第二个参数我们要使用 MATCH_DEFAULT_ONLY 这个标记位,这个标记位的含义是仅仅匹配那些在 intent-filter 中声明 <category android:name="android.intent.category.DEFAULT"/> 这个 catefory的Activity。使用的意义在于只要上述两个方法不返回 null,则 startActivity 一定可以成功。如果不用这个标记位,就可以把 intent-filter 中 category 不含 DEFAULT 的那些Activity 匹配出来,从而导致 startActivity 失败。因为不含 DEFAULT 这个 category 的Activity 是无法接收隐式 Intent 的。针对 Service 和BroadcastReceiver,PackageManager 同样提供了类似的方法去获取匹配的组件信息。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值