主流程
- 主線流程:先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]