Android 4.2源码 IntentFilter.java
Intent可以用于启动Android四大组件中的三个(Activity、Service和Receiver,这里不包含Provider)。
启动的方法包括:
启动Activity:Context.startActivity()和Activity.startActivityForResult()
启动Srevice:Context.startService() 和Context.bindService()
启动Receiver:Context.sendBroadcast()、Context.sendOrderedBroadcast()和Context.sendStickyBroadcast()
启动的方式有两种:显示启动和隐式启动。
显式启动:在Intent中指明了ComponentName,关于这部分没有什么可讨论的,直接就会启动对应的组件。
隐式启动:在Intent中没有指明ComponentName,这部分则是我们要讨论的重点。每个组件都需要在AndroidManifest.xml文件中声明,在声明的时候会指明一些Intent Filter,当某个Intent能够和其中某个Intent Filter匹配时就会启动这个组件。类似这样的声明: <intent-filter>
有个例外,broadcast receivers可以不在AndroidManifest.xml中声明,而在代码中通过Context.registerReceiver()去注册,Activity和Service必须在AndroidManifest.xml文件中声明。
一个组件可能含有零个、一个或多个Intent Filter。
如果含有零个,则只能通过显示地启动这个组件;
如果含有一个,则只要Intent能通过这个Intent Filter的检查,就能启动这个组件;
如果含有多个,则只要Intent能通过任意一个Intent Filter的检查,就能启动这个组件。
接下来将分析Intent Filter对Intent的匹配检查。
匹配检查分为三步:
1.Action test;
2.Category test;
3.Data test.
三步检查都通过才能够算是成功,否则即为失败。
注:我们知道一个Intent还包括Extras、Flags等信息,这些信息在匹配的过程中会被忽略,匹配过程不需要这些信息。因为Intent Filter中并没有这些信息,因此不会去检查。
对于Intent,它至多包含一个Action,可以没有Action;
对于Intent Filter,则可以包含一系列Action,当然也可以没有Action。
如果Intent中不包含Action,则这项test直接通过;
如果Intent Filter不包含任何Action,则所有的Intent都不能通过这项test;
如果Intent Filter包含Intent的Action,则通过test。
有个疑问,如果Intent和Intent Filter都没有Action,则是通过还是Fail呢?
两种解释,似乎有些矛盾:
解释一:来自Android API--http://developer.android.com/guide/components/intents-filters.html
If the filter fails to list any actions, there is nothing for an intent to match, so all intents fail the test. No intents can get through the filter.
On the other hand, an Intent object that doesn't specify an action automatically passes the test — as long as the filter contains at least one action.
意思是:只要Intent Filter包含至少一个Action,则不包含Action的Intent就可以通过;如果都不包含Action,则会Fail。
解释二:Android 4.2源码 MTK 6572平台 IntentFilter.java
public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag) { //这里只有在以下情形下才会return NO_MATCH_ACTION //Intent的action不为空,且Intent Filter中不包含这个action //换言之,如果Intent的action为空,则根本不做任何检查,那就是通过了Action test if (action != null && !matchAction(action)) { if (false) Log.v( logTag, "No matching action " + action + " for " + this); return NO_MATCH_ACTION; } …… }
public final boolean matchAction(String action) { return hasAction(action); } public final boolean hasAction(String action) { //private final ArrayList<String> mActions; //这里似乎action为空则返回false,但是在action为空时match方法根本不会调用这个方法去检查 return action != null && mActions.contains(action); }
//return null则表明通过了Category test public final String matchCategories(Set<String> categories) { //如果Intent中没有category,那么直接就通过了Category test if (categories == null) { return null; } Iterator<String> it = categories.iterator(); //如果Intent中有Category,而Filter中一个Category也没有,那么就不能通过Category test if (mCategories == null) { return it.hasNext() ? it.next() : null; } //如果Intent中有Filter中不存在的Category,那么test fail while (it.hasNext()) { final String category = it.next(); if (!mCategories.contains(category)) { return category; } } return null; }
下面来看match的源码(重点看matchData的test)
public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag) { //Firstly, Action test if (action != null && !matchAction(action)) { //Action test fail return NO_MATCH_ACTION; } //Secondly, Data test int dataMatch = matchData(type, scheme, data); if (dataMatch < 0) { //Data test fail return dataMatch; } //Finally, Category test String categoryMismatch = matchCategories(categories); if (categoryMismatch != null) { //Category test fail return NO_MATCH_CATEGORY; } return dataMatch; }
public final int matchData(String type, String scheme, Uri data) { final ArrayList<String> types = mDataTypes; final ArrayList<String> schemes = mDataSchemes; final ArrayList<AuthorityEntry> authorities = mDataAuthorities; final ArrayList<PatternMatcher> paths = mDataPaths; int match = MATCH_CATEGORY_EMPTY; //case 1:Intent Filter has neither types nor URI(a meaningful URI must has scheme) if (types == null && schemes == null) { //if Intent has no type and no scheme then it will pass this test return ((type == null && data == null) ? (MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL) : NO_MATCH_DATA); } //case 2:Intent Filter has URI(schemes) if (schemes != null) { //firstly, Intent must has scheme which can be found in Intent Filter's schemes //这里如果能够成功,此时匹配成功的级别是MATCH_CATEGORY_SCHEME if (schemes.contains(scheme != null ? scheme : "")) { match = MATCH_CATEGORY_SCHEME; } else { return NO_MATCH_DATA; } //secondly, 通过了scheme test后,如果Filter有authority,那么就进入到authority test //如果Intent Filter没有authority,那么这里的authority测试就直接pass了 if (authorities != null) { //Intent Filter has authority, so you must match Data Authority int authMatch = matchDataAuthority(data); if (authMatch >= 0) { //现在你通过了authority test,接下来看是否需要进入到path test if (paths == null) { match = authMatch; } else if (hasDataPath(data.getPath())) { //path test通过,匹配成功的级别升级为MATCH_CATEGORY_PATH match = MATCH_CATEGORY_PATH; } else { return NO_MATCH_DATA; } } else { return NO_MATCH_DATA; } } } else { //如果Filter没有scheme,那么Intent若也没有scheme,则pass;若有,则必须为空,或content、或file,否则fail test if (scheme != null && !"".equals(scheme) && !"content".equals(scheme) && !"file".equals(scheme)) { return NO_MATCH_DATA; } } if (types != null) { //匹配data 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) { return NO_MATCH_TYPE; } } return match + MATCH_ADJUSTMENT_NORMAL; }