Android Intent匹配规则

Android Intent在整个Android系统使用非常广泛,如startActivity,startService,广播的发送等等都会用到Intent,以广播为例,广播的发送方sendBroadcast(Intent),那AMS是如何匹配对应的BroadcastReceiver的呢?
影响Intent匹配规则的有3个关键因素:
1.Action
2.Category
3.Data
广播接收器可以声明一个IntentFilter或者多个IntentFilter,但是只要一个IntentFilter满足要求,就可以匹配。这个同样适用于其余的组件(Activity,Service)。

IntentFilter.match

public final int match(String action, String type, String scheme,
            Uri data, Set<String> categories, String logTag) {
    if (action != null && !matchAction(action)) {
        return NO_MATCH_ACTION;
    }    

    int dataMatch = matchData(type, scheme, data);
    if (dataMatch < 0) { 
        return dataMatch;
    }    

    String categoryMismatch = matchCategories(categories);
    if (categoryMismatch != null) {
        return NO_MATCH_CATEGORY;
    }    
    return dataMatch;
}

在该函数中
1.如果action为空,则继续;如果action不为空,则调用matchAction,匹配Action,如果不匹配,则返回
2.调用matchData,如果返回值dataMatch大于0,则继续,否则返回
3.调用matchCategories,如果返回为空,则通过,否则不通过

从整个流程来看,影响匹配的因素就是action,data,和categories

Action匹配

public final boolean matchAction(String action) {
    return hasAction(action);
}

public final boolean hasAction(String action) {
    //如果Intent的action不为空,则其必须是IntentFilter的actions的子集
    return action != null && mActions.contains(action);
}

matchAction调用hasAction,在hasAction主要是判断mActions是否包含该action,mActions是一个ArrayList。IntentFilter可以通过addAction,将多个action保存在list中。

Action匹配还是比较简单的:
- 如果Intent没有action,则通过
- 如果Intent有action,filter没有action,则不通过
- 如果Intent有action,filter有action,则前者必须是后者的子集才能通过
可以用集合来概况,Intent的Action必须是IntentFilter的actions的子集,尤其针对第一点,空集是任何集合的子集,所以第一点通过。

Data匹配

Data主要包含两个部分:MIME,URI

MIME(Multipurpose Internet Mail Extensions)最早是电子邮件协议(SMTP)所规定的邮件的文件格式类型,后来逐渐被运用于其他的多种互联网协议(HTTP等)。
MIME用于指明某段数据是什么格式类型,以保证程序能够正确处理和解析

URI(Uniform resource identifier)是某种资源的全球唯一定位标志,因此多用于网络环境中,格式如下
Android Intent匹配规则_第1张图片
其中scheme不仅包括了http等网络协议,还有android自定义的content来表示ContentProvider所提供的数据。host是主机的名称,port指通信端口,两者统称为Authority,如果host不存在,则port会被忽略。最后一个path是文件路径,表示该资源在host中的具体的位置

如果scheme没有指定,则authority和path都没有意义
如果scheme和authority没有指定,则path没有意义

IntentFilter没有指定MIME和URI,Intent也没有指定MIME和URI,则通过测试,否则不匹配

MIME

IntentFilter没有指定,Intent没有指定,通过;否则不通过
IntentFilter有指定,Intent没有指定MIME,则不通过;如果指定了,必须是下面5种情形才通过
1. 要么Intent的MIME要么是IntentFilter的子集
2. 要么Intent的MIME是”*/*”;
3. 要么IntentFilter的MIME是”*/*”
4. 要么IntentFilter包含”xx/*”,并且Intent的MIME斜杠前面的内容相同;
5. 要么Intent是”xx/*”,并且IntentFilter中的某个MIME匹配xx/

URI

scheme匹配

IntentFilter的schemes为空,则通过
IntentFilter的scheme不为空,
1. Intent的scheme必须不为空,并且是IntentFilter的schemes的子集
2. 如果IntentFilter存在ssp(scheme-specified part),ssp匹配,则通过
3. 如果IntentFilter与Intent的data部分ssp不匹配,则测试Authority部分,如果匹配,测试path部分,如果IntentFilter不存在path或者跟Intent匹配,则通过

SSP和Path的匹配部分同样遵循GLOB规则(见Android PatternMatcher)

categories匹配

public final String matchCategories(Set<String> categories) {
    //Intent的categories为空,返回空表示匹配
    if (categories == null) {
        return null;
    }
    Iterator<String> it = categories.iterator();
    //Intent的categories不为空,但是IntentFilter的mCategories为空,不匹配
    if (mCategories == null) {
        return it.hasNext() ? it.next() : null;
    }
    //Intent和IntentFilter的categories均不为空,则前者是后者的子集则匹配,否则不匹配
    while (it.hasNext()) {
        final String category = it.next();
        if (!mCategories.contains(category)) {
            return category;
        }
    }
    return null;
}
  1. 如果Intent的categories为空,则匹配
  2. 如果Intent的categories不为空,IntentFilter的categories为空,则不匹配
  3. 如果Intent的categoreis不为空,IntentFilter的categories不为空,则前者必须是后者的子集才匹配,否则不匹配

可以用集合来概况,Intent的categories必须是IntentFilter的categories的子集,尤其针对第一点,空集是任何集合的子集,所以第一点通过。跟前面的Action的匹配是一样的。

总结:

影响IntentFilter的匹配规则的有三个方面:Action,Data,Category。其中Action和Category必须满足Intent中的Action和Category必须是IntentFilter中的Action和Category的子集(空集是任何集合的子集)。Data比较复杂,Data分为MIME和Uri,如果Intent和IntentFilter均为空,则匹配,否则IntentFilter中存在的部分必须匹配。

特别的:如果Intent和IntentFilter的Action,Data,Category均为空,也是匹配的。

你可能感兴趣的:(android)