关于Intent以及IntentFilter的基本知识,大家可以参阅如下资料,
SDK中对Intent与IntentFilter的介绍 ---- 英文
其中文翻译如下:
Android开发之旅:
Intents和Intent Filters(理论部分)
我重点分析一下两个方面:
第一部分 、Intent以及IntentFilter说明以及匹配规则分析
第一部分 、Intent以及IntentFilter说明以及匹配规则分析
想当初我看Intent相关知识时,对Intent、IntentFilter的理解就很差劲,总觉得系统定义了一个Intent,为何还要整理个
IntentFilter出来"祸害"广大程序猿呢?但不解归不解,在具体使用咱可不能含糊,于是只好依葫芦画瓢了,反正绝对还不错。
一、温故而知新
:Intent与IntentFilter两问。
主要功能是根据特定的条件找到匹配的组件,继而对该组件执 行一些操作。比如执行startActivity()时,系统
:主要功能是为某个组件向系统注册一些特性(当然一个组件可以注册多个IntentFilter),以便Intent找到对应
二、它们之间的关系是如何呢?
- public class Intent implements Parcelable, Cloneable {
- private String mAction; //action值
- private Uri mData; //uri
- private String mType; //MimeType
- private String mPackage; //所在包名
- private ComponentName mComponent; //组件信息
- private int mFlags; //Flag标志位
- private HashSet<String> mCategories; //Category值
- private Bundle mExtras; //附加值信息
- //...
- }
public class Intent implements Parcelable, Cloneable { private String mAction; //action值 private Uri mData; //uri private String mType; //MimeType private String mPackage; //所在包名 private ComponentName mComponent; //组件信息 private int mFlags; //Flag标志位 private HashSet<String> mCategories; //Category值 private Bundle mExtras; //附加值信息 //... }
IntentFilter类源码(部分) 路径位于:\frameworks\base\core\java\android\content\IntentFilter.java
- public class IntentFilter implements Parcelable {
- //...
- //保存了所有action字段的值
- private final ArrayList<String> mActions;
- //保存了所有Category的值
- private ArrayList<String> mCategories = null;
- //保存了所有Schema(模式)的值
- private ArrayList<String> mDataSchemes = null;
- //保存了所有Authority字段的值
- private ArrayList<AuthorityEntry> mDataAuthorities = null;
- //保存了所有Path的值
- private ArrayList<PatternMatcher> mDataPaths = null;
- //保存了所有MimeType的值
- private ArrayList<String> mDataTypes = null;
- //...
- }
public class IntentFilter implements Parcelable { //... //保存了所有action字段的值 private final ArrayList<String> mActions; //保存了所有Category的值 private ArrayList<String> mCategories = null; //保存了所有Schema(模式)的值 private ArrayList<String> mDataSchemes = null; //保存了所有Authority字段的值 private ArrayList<AuthorityEntry> mDataAuthorities = null; //保存了所有Path的值 private ArrayList<PatternMatcher> mDataPaths = null; //保存了所有MimeType的值 private ArrayList<String> mDataTypes = null; //... }
PS :大家可以参详下Intent与IntentFilter类中不同字段的属性类型。Intent中属性类型基本上都是单个类型的,而IntentFilter
属性都是集合类型的。从这方面思考,更可以加深我们的理解。
三、Intent匹配规则
匹配种类有如下三种:
比较好理解的是,进行匹配时Intent携带的Action字段值和Category字段值必须包含在IntentFilter中,否则匹配失败。
SDK中说明的具体规则如下:
PS :可别说我不会总结出来给大家分享,其实我觉得很多知识都需要自己去尝试,去努力吸收,只要经过自己的消化,
学到的知识就是自己的了。
上面的规则比较生硬吧。我们去源码中去看看Intent与IntentFilter的具体匹配方法吧。
该方法是IntentFilter中的match()方法,该方法的内部处理逻辑就是按照上面的规则去判断的,大家可以仔细体味下,该方法
我们在后面讲到Intent解析过程时也会用到。 具体逻辑在代码中进行了说明。
- public class IntentFilter implements Parcelable {
- //匹配算法,,按照匹配规则进行
- //Intent与该IntentFilter进行匹配时调用该方法参数表示Intent的相关属性值
- public final int match(String action, String type, String scheme,
- Uri data, Set<String> categories, String logTag){
- //首先、匹配Action字段
- if (action != null && !matchAction(action)) {
- if (Config.LOGV) Log.v(
- logTag, "No matching action " + action + " for " + this);
- return NO_MATCH_ACTION;
- }
- //其次、匹配数据(Uri和MimeType)字段
- int dataMatch = matchData(type, scheme, data);
- //...
- //最后,匹配Category字段值
- String categoryMatch = matchCategories(categories);
- //...
- }
- //...
- }
public class IntentFilter implements Parcelable { //匹配算法,,按照匹配规则进行 //Intent与该IntentFilter进行匹配时调用该方法参数表示Intent的相关属性值 public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag){ //首先、匹配Action字段 if (action != null && !matchAction(action)) { if (Config.LOGV) Log.v( logTag, "No matching action " + action + " for " + this); return NO_MATCH_ACTION; } //其次、匹配数据(Uri和MimeType)字段 int dataMatch = matchData(type, scheme, data); //... //最后,匹配Category字段值 String categoryMatch = matchCategories(categories); //... } //... }
第二部分、 Intent的解析过程分析
一、引入PackageManager
我们知道Android源码总是贴心的(不知道有没有10086贴心),它对外提供了很多借口供应用程序调用,例如AudioManger
(音频管理)、TelephoneManger(电话管理)、同样也提供了一个包管理-----PackageManager,通过它我们可以、获取应用
程序包得信息,例如图标、Lable标签等。具体关于PackageManager的使用,可以参考我的另外一篇文章 :
<<Android中获取应用程序(包)的信息-----PackageManager的使用(一)>>
二、PackageManagerService ---- 重量级选手
前面所说PackageManager不过是个傀儡,所有相关的操作都是由PackageManagerService 完成的。这儿我们简单的
分析下PackageManagerService 的特性:
①、开机就启动,由SystemServer进程启动 ;
②、启动后它会扫描系统中所有应用程序Apk包下的AndroidManifest.xml文件,然后解析所有的
AndroidManifest.xml文件,继而形成一个庞大的信息结构树,并且保存在PackageManagerService
的相关属性下。
它会扫描这两个目录:
/system/app ------------------> 系统应用程序
/data/app ------------------> 第三方应用程序(所有安装的Apk包都会在该目录下保存一份拷贝)
扫描完成后,于是所有的信息结构就构建了。PackageManagerService 的四个重要属性如下:
- class PackageManagerService extends IPackageManager.Stub {
- //...
- //保存了所有Activity节点信息 。 自定义类
- // All available activities, for your resolving pleasure.
- final ActivityIntentResolver mActivities =
- new ActivityIntentResolver();
- //保存了所有BroadcastReceiver节点信息 。 自定义类
- // All available receivers, for your resolving pleasure.
- final ActivityIntentResolver mReceivers =
- new ActivityIntentResolver();
- //保存了所有Service节点信息。 。 自定义类
- // All available services, for your resolving pleasure.
- final ServiceIntentResolver mServices = new ServiceIntentResolver();
- //保存了所有ContentProvider节点信息 , 以Hash值保存
- // Keys are String (provider class name), values are Provider.
- final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =
- new HashMap<ComponentName, PackageParser.Provider>();
- //...
- }
class PackageManagerService extends IPackageManager.Stub { //... //保存了所有Activity节点信息 。 自定义类 // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = new ActivityIntentResolver(); //保存了所有BroadcastReceiver节点信息 。 自定义类 // All available receivers, for your resolving pleasure. final ActivityIntentResolver mReceivers = new ActivityIntentResolver(); //保存了所有Service节点信息。 。 自定义类 // All available services, for your resolving pleasure. final ServiceIntentResolver mServices = new ServiceIntentResolver(); //保存了所有ContentProvider节点信息 , 以Hash值保存 // Keys are String (provider class name), values are Provider. final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent = new HashMap<ComponentName, PackageParser.Provider>(); //... }
- @Override
- public PackageManager getPackageManager() {
- //...
- // Doesn't matter if we make more than one instance.
- return (mPackageManager = new ApplicationPackageManager(this, pm));
- //...
- }
- class ContextImpl extends Context {
- //...
- /*package*/
- static final class ApplicationPackageManager extends PackageManager{
- //...
- @Override
- public ActivityInfo getActivityInfo(ComponentName className, int flags){
- //...
- }
- }
- //...
- }
@Override public PackageManager getPackageManager() { //... // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); //... } class ContextImpl extends Context { //... /*package*/ static final class ApplicationPackageManager extends PackageManager{ //... @Override public ActivityInfo getActivityInfo(ComponentName className, int flags){ //... } } //... }
三 、保存数据采用的数据结构和解析算法
1、保存数据采用的数据结构
作用:保存了每个<intent-filter>节点信息
ActivityIntentInfo类:继承至IntentInfo类
作用:保存了<activity />节点下的<
intent-filter>节点信息
ServiceIntentInfo:继承至IntentInfo类
作用:保存了<service />节点下的<
intent-filter >节点信息
Activity类:保存了<activity />节点信息
Service类:保存了<service />节点信息
PS:这些都是PackageParser类的内部类
。PackageParser的主要功能就是解析AndroidManifest.xml文件
IntentResolver类:模板类,父类,保存了<activity/>、<service/>、<receiver
/>节点的共同信息。
ActivityIntentResolver类:继承至IntentResolver类。
作用:保存了所有<activity/>或者<receiver/>节点信息。(Activity或者BroadcastReceiver信息就是用该自定义类保存的)
ServiceIntentResolver类:继承至IntentResolver类,保存了
作用:保存了所有<service/>节点信息。(Service信息就是用该自定义类保存的)。
一个简单的UML图表示如下:
2、Intent解析采用的算法
不同的数据结构决定了不同的算法,而不同的算法又决定着性能,例如时间复杂度以及空间复杂度等。 在具体讲解解析
采用的算法时,我们先理解下这个情景。
假设一个女人决定参加一个相亲节目(大家可以理解成《非诚勿扰》),然后她向主办方提出如下条件:
1、身高 ? 175cm以上 ;
2、 财富 ? 100万 ;
3、 学历 ? 本科以上 ;
……
主办发经理一看,你丫的要求还真高。但客户是万能的,该经理也只能去找到满足这些条件的男人咯。
最开始,该经理是这么想的,我把所有男的都给遍历一遍,肯定把满足这些条件的男人给揪出来。他找啊找,觉得这么找下去
是不是太二B了(呵呵,你也是这么想的吗?)。经理就开始想:“我为什么不能根据这些条件把所有男的给分成三个种群呢?有钱
的男人在一起,高个子的男人在一起,高学历的男人在一起,这样查找起来不是更快吗 ? “
于是,有了如下的划分: PS, 你是属于哪一类额 ?
二B算法(没有分类)
高级点的算法(分类后)
可能大家对这种根据关键值分类的好处不能一目了然。我们举个一般例子吧:
假设当前共有100个男的。 其中有钱的有20人,高个子有30人,高学历男人有10人。
根据第一种算法分类,我们需要比较100次,而第二种算法我们总共只需要比较60次。从整个基数来分析,算法肯定优化了
最后,对不同的分类中查询的结果进行组合重新排列下,即可得到我们的满足该女性的要求。
同样的,在进行Intent匹配时,Android也采用了第二种方法来进行算法匹配。它根据一些关键值Action、MimeType、
Schema字段去进行分类。分类之后的集合大致如下:
于是在进行具体匹配时,我们只是需要根据关键值从不同集合中获取即可。
事实上,由于MimeType的通配符(*)的特性,它的匹配可以说是最难的。参考IntentResolver类,真正的关键值如下:
- //模板类 F类型可能为ActivityIntentInfo或ServiceIntentInfo,R对象是ResolverInfo类
- public class IntentResolver<F extends IntentFilter, R extends Object> {
- //保存了所有<intent-filter>节点信息
- //All filters that have been registered.
- private final HashSet<F> mFilters = new HashSet<F>();
- /** All of the MIME types that have been registered, such as "image/jpeg",
- * "image/*", or "{@literal *}/*".
- */
- //关键值表示MimeType形如: image/jpeg 、 image/*、/* 类型
- private final HashMap<String, ArrayList<F>> mTypeToFilter
- /**
- * The base names of all of all fully qualified MIME types that have been
- * registered, such as "image" or "*". Wild card MIME types such as
- * "image/*" will not be here.
- */
- //关键值表示MimeType形如:image、 image/*、* 类型
- private final HashMap<String, ArrayList<F>> mBaseTypeToFilter
- /**
- * The base names of all of the MIME types with a sub-type wildcard that
- * have been registered. For example, a filter with "image/*" will be
- * included here as "image" but one with "image/jpeg" will not be
- * included here. This also includes the "*" for the "{@literal *}/*"
- * MIME type.
- */
- //这个关键字段表示MimeType形如 :image、* 类型
- private final HashMap<String, ArrayList<F>> mWildTypeToFilter
- //All of the URI schemes (such as http) that have been registered.
- //关键值字段表示Schema
- private final HashMap<String, ArrayList<F>> mSchemeToFilter
- /**
- * All of the actions that have been registered, but only those that did
- * not specify data.
- */
- //关键值字段表示:Action
- private final HashMap<String, ArrayList<F>> mActionToFilter
- //All of the actions that have been registered and specified a MIME type.
- //关键值字段表示:Action和MimeType。 即该<intent-filter>节点必须包含action和MimeType
- private final HashMap<String, ArrayList<F>> mTypedActionToFilter
- }
//模板类 F类型可能为ActivityIntentInfo或ServiceIntentInfo,R对象是ResolverInfo类
public class IntentResolver<F extends IntentFilter, R extends Object> {
//保存了所有<intent-filter>节点信息
//All filters that have been registered.
private final HashSet<F> mFilters = new HashSet<F>();
/** All of the MIME types that have been registered, such as "image/jpeg",
* "image/*", or "{@literal *}/*".
*/
//关键值表示MimeType形如: image/jpeg 、 image/*、/* 类型
private final HashMap<String, ArrayList<F>> mTypeToFilter/**
* The base names of all of all fully qualified MIME types that have been
* registered, such as "image" or "*". Wild card MIME types such as
* "image/*" will not be here.
*/
//关键值表示MimeType形如:image、 image/*、* 类型
private final HashMap<String, ArrayList<F>> mBaseTypeToFilter/**
* The base names of all of the MIME types with a sub-type wildcard that
* have been registered. For example, a filter with "image/*" will be
* included here as "image" but one with "image/jpeg" will not be
* included here. This also includes the "*" for the "{@literal *}/*"
* MIME type.
*/
//这个关键字段表示MimeType形如 :image、* 类型
private final HashMap<String, ArrayList<F>> mWildTypeToFilter//All of the URI schemes (such as http) that have been registered.
//关键值字段表示Schema
private final HashMap<String, ArrayList<F>> mSchemeToFilter
/**
* All of the actions that have been registered, but only those that did
* not specify data.
*/
//关键值字段表示:Action
private final HashMap<String, ArrayList<F>> mActionToFilter
//All of the actions that have been registered and specified a MIME type.
//关键值