您的位置:首页 > 其它

Intent Filter match过程源码分析

2015-08-06 21:05 435 查看

主流程

主线流程:先match action, 再match data, 最后match category

时序图


简化后的代码

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;
}


子流程

match action

这个子流程很简单,只判断action是否包含在intent filter

代码

/**
 * Match this filter against an Intent's action.  If the filter does not
 * specify any actions, the match will always fail.
 *
 * @param action The desired action to look for.
 *
 * @return True if the action is listed in the filter.
 */
public final boolean matchAction(String action) {
    return hasAction(action);
}

public final boolean hasAction(String action) {
    return action != null && mActions.contains(action);
}


match data

这个子流程稍显复杂,代码出口太多,结合uri的语法组成来看[scheme:]scheme-specific-part[#fragment] / [scheme:][//authority][path][?query][#fragment]

代码

/**
 * Match this filter against an Intent's data (type, scheme and path). If
 * the filter does not specify any types and does not specify any
 * schemes/paths, the match will only succeed if the intent does not
 * also specify a type or data.  If the filter does not specify any schemes,
 * it will implicitly match intents with no scheme, or the schemes "content:"
 * or "file:" (basically performing a MIME-type only match).  If the filter
 * does not specify any MIME types, the Intent also must not specify a MIME
 * type.
 *
 * <p>Be aware that to match against an authority, you must also specify a base
 * scheme the authority is in.  To match against a data path, both a scheme
 * and authority must be specified.  If the filter does not specify any
 * types or schemes that it matches against, it is considered to be empty
 * (any authority or data path given is ignored, as if it were empty as
 * well).
 *
 * <p><em>Note: MIME type, Uri scheme, and host name matching in the
 * Android framework is case-sensitive, unlike the formal RFC definitions.
 * As a result, you should always write these elements with lower case letters,
 * and normalize any MIME types or Uris you receive from
 * outside of Android to ensure these elements are lower case before
 * supplying them here.</em></p>
 *
 * @param type The desired data type to look for, as returned by
 *             Intent.resolveType().
 * @param scheme The desired data scheme to look for, as returned by
 *               Intent.getScheme().
 * @param data The full data string to match against, as supplied in
 *             Intent.data.
 *
 * @return Returns either a valid match constant (a combination of
 * {@link #MATCH_CATEGORY_MASK} and {@link #MATCH_ADJUSTMENT_MASK}),
 * or one of the error codes {@link #NO_MATCH_TYPE} if the type didn't match
 * or {@link #NO_MATCH_DATA} if the scheme/path didn't match.
 *
 * @see #match
 */
public final int matchData(String type, String scheme, Uri data) {
    final ArrayList<String> types = mDataTypes;
    final ArrayList<String> schemes = mDataSchemes;

    int match = MATCH_CATEGORY_EMPTY;

    //1. 若filter的type scheme为空,且intent的type data也为空则匹配
    //   否则不匹配
    if (types == null && schemes == null) {
        return ((type == null && data == null)
            ? (MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL) : NO_MATCH_DATA);
    }

    if (schemes != null) {
    //2. 若filter的schemes不为空且intent的scheme包含在里面则进行后续判断;
    //   否则不匹配
        if (schemes.contains(scheme != null ? scheme : "")) {
            match = MATCH_CATEGORY_SCHEME;
        } else {
            return NO_MATCH_DATA;
        }

        final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
        if (schemeSpecificParts != null) {
        //3. 若schemeSpecificParts不为空,则用data的SchemeSpecificPart来做匹配
        //   并修改match的值。uri语法:[scheme:]scheme-specific-part[#fragment] / [scheme:][//authority][path][?query][#fragment]
            match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
                    ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
        }
        if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
            // If there isn't any matching ssp, we need to match an authority.
            final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
            // 4. 若schemeSpecificPart(ssp)不匹配,则要匹配authority
            // 也就是判断host port部分
            if (authorities != null) {
                int authMatch = matchDataAuthority(data);
                if (authMatch >= 0) {
                // 5. host port匹配,则继续进行path的匹配
                    final ArrayList<PatternMatcher> paths = mDataPaths;
                    if (paths == null) {
                        match = authMatch;
                    } else if (hasDataPath(data.getPath())) {
                        match = MATCH_CATEGORY_PATH;
                    } else {
                        return NO_MATCH_DATA;
                    }
                } else {
                // host port不匹配
                    return NO_MATCH_DATA;
                }
            }
        }
        // If neither an ssp nor an authority matched, we're done.
        if (match == NO_MATCH_DATA) {
            return NO_MATCH_DATA;
        }
    } else {
    // filter的schemeSpecificParts不为空且和intent的SchemeSpecificPart匹配时,
    // 若scheme不是"" "content" "file" 就不匹配;否则继续后续判断
        // Special case: match either an Intent with no data URI,
        // or with a scheme: URI.  This is to give a convenience for
        // the common case where you want to deal with data in a
        // content provider, which is done by type, and we don't want
        // to force everyone to say they handle content: or file: URIs.
        if (scheme != null && !"".equals(scheme)
                && !"content".equals(scheme)
                && !"file".equals(scheme)) {
            return NO_MATCH_DATA;
        }
    }

    if (types != null) {
    // 6. type即MIME
    // 若type不为空则判断filter和intent的type是否包容,否则不匹配
        if (findMimeType(type)) {
            match = MATCH_CATEGORY_TYPE;
        } else {
            return NO_MATCH_TYPE;
        }
    } else {
        // If no MIME types are specified, then we will only match against
        // an Intent that does not have a MIME type.
        if (type != null) {
    // 若filter的types集合是空,但intent的不是空,不匹配
            return NO_MATCH_TYPE;
        }
    }

    return match + MATCH_ADJUSTMENT_NORMAL;
}


match category

这个子流程也不复杂,只判断intent的category是否完全包含在filter里

代码

/**
 * Match this filter against an Intent's categories.  Each category in
 * the Intent must be specified by the filter; if any are not in the
 * filter, the match fails.
 *
 * @param categories The categories included in the intent, as returned by
 *                   Intent.getCategories().
 *
 * @return If all categories match (success), null; else the name of the
 *         first category that didn't match.
 */
public final String matchCategories(Set<String> categories) {
    if (categories == null) {
        return null;//匹配成功
    }

    Iterator<String> it = categories.iterator();

    if (mCategories == null) {//filter没有Categories;intent有则失败,无则成功
        return it.hasNext() ? it.next() : null;
    }

    while (it.hasNext()) {//filter有Categories, intent的Categories要全部包含在filter里才算成功
        final String category = it.next();
        if (!mCategories.contains(category)) {
            return category;
        }
    }

    return null;
}


小结

匹配过程总体分三步走,match action-> match data-> match categories,任意一步失败就不在进行后续处理。

match action就是匹配intent的action是否包含在filter的actions里。

match data的思路和uri的语法组成有关[scheme:]scheme-specific-part[#fragment]

先判filter和intent的types(即MIMI) schemes是否全是null,若是则匹配,取值MATCH_CATEGORY_EMPTY,否则继续

再匹配scheme,不匹配则结束,匹配则继续

SchemeSpecificPart部分,若匹配,则进行最后的type(MIME)判断

SchemeSpecificPart部分,若不匹配,则

匹配host port部分,成功则继续,否则不匹配

匹配path部分,成功则继续,否则不匹配

最后进行type(MIME)的匹配

match categories就是判断intent的所有category是否全都包含啊filter的categories里。

uri的语法组成[scheme:]scheme-specific-part[#fragment] / [scheme:][//authority][path][?query][#fragment]

参考

http://www.cjsdn.net/doc/jdk50/java/net/URI.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: