Intent-Filter匹配规则

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 同样提供了类似的方法去获取匹配的组件信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值