Intent类的注释:
一个intent是要被执行的操作的一种抽象的描述,结合Context.java类中定义的几个方法 ——
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public abstract void startActivity(Intent intent); public abstract void sendBroadcast(Intent intent); public abstract ComponentName startService(Intent service); public abstract boolean bindService(Intent service, ServiceConnection conn, int flags);</span></span>
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public Intent() { } public Intent(String action) { setAction(action); /*public Intent setAction(String action) { mAction = action != null ? action.intern() : null; return this; }*/ } public Intent(String action, Uri uri) { setAction(action); mData = uri; } public Intent(Context packageContext, Class<?> cls) { mComponent = new ComponentName(packageContext, cls); }</span></span>在这些构造方法中,主要的操作就是为Intent的成员变量赋值,Intent类的成员变量主要有:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">private String mAction; private Uri mData; private ComponentName mComponent; private int mFlags; private ArraySet<String> mCategories; private Bundle mExtras; ... ...</span></span>事实上,除了在构造函数中为这些成员变量赋值,还可以利用下列方法为对应的成员变量赋值:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public Intent setAction(String action) { } public Intent setData(Uri data) { } public Intent setComponent(ComponentName component) { } public Intent setClassName(Context packageContext, String className) { } public Intent setFlags(int flags) { } public Intent addCategory(String category) { }</span></span>
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public Intent setComponent(ComponentName component) { mComponent = component; return this; }</span></span>该方法接收一个ComponentName 类型的参数,ComponentName 类有三个构造函数:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public ComponentName(String pkg, String cls) { } public ComponentName(Context pkg, String cls) { } public ComponentName(Context pkg, Class<?> cls) { }</span></span>由这三个构造函数可知,指定包名和类名便可确定一个组件,事实上,设置Component属性的目的就是指定一个Intent将要被用来与哪个组件进行通信。以下3句代码创建了一个Intent对象,并指定了它的Component属性:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">ComponentName comp =new ComponentName(this,OtherActivity.class); Intent mIntent = new Intent(); mIntent.setComponent(comp); </span></span>除了上述这种方式,还可以这样做:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">Intent mIntent = new Intent(this,OtherActivity.class);</span></span>也可以这样做:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">Intent mIntent = new Intent(); mIntent.setClassName(this,OtherActivity); // 我们看到setClassName(Context packageContext, String className)方法 // 内部调用了mComponent = new ComponentName(packageContext, className); </span></span>
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public Intent addCategory(String category) { if (mCategories == null) { mCategories = new ArraySet<String>(); } mCategories.add(category.intern()); return this; }</span></span>
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">public Intent putExtra(String name, boolean value) { if (mExtras == null) { mExtras = new Bundle(); } mExtras.putBoolean(name, value); return this; }</span></span>B、
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">Bundle mBundle = new Bundle(); mBundle.putBoolean(... ...); mIntent .putExtras(mBundle); /*public Intent putExtras(Bundle extras) { if (mExtras == null) { mExtras = new Bundle(); } mExtras.putAll(extras); return this; }*/</span></span>
IntentFilter通常被使用在应用程序的清单文件中,在一个组件内部以intent-filter节点的形式来定义,采用白名单管理,即只列出愿意接受的intent。
那么,这里就涉及到一个匹配规则的问题。
Android组件可以有一个或多个IntentFilter,每个IntentFilter之间相互独立,一个intent只需要和其中一个IntentFilter匹配上即可,而只有一个intent的action、Category 和data都同时和某个IntentFilter相匹配,才能认为这个intent和IntentFilter相匹配。
一、action的验证:
只要intent设置的action全部来源于某个IntentFilter当中,则匹配成功,需要注意的是,如果intent中没有指定action,那么匹配失败。而且区分大小写。
二、Category的验证:如果Intent中的Category集合是Intentfilter中Category的集合的子集时,Intent能通过检查。另外,系统在调用startActivity和startActivityForResult时默认会给所有 Intent 配置 “android.intent.category.DEFAULT” category。所以只要是想接收一个隐式 Intent 的 IntentFilter都应该包括 "android.intent.category.DEFAULT" category,不然将导致 Intent 匹配失败。
三、data的验证(主要参考任玉刚的《Android开发艺术探索》一书,谢谢作者):
和action类似,如果过滤规则中定义了data,那么intent中也需要有可匹配的data,data的结构为:
data由两部分组成,mimeType和URI,mimeType指数据类型,比如image/jpeg、audio/mpeg4-generic和video/*等,可以表示图片、文本、视频等不同的媒体格式,而URI的结构为:
scheme://host:port/path/pathPrefix/pathPattern,如:
content://com.example.project:200/folder/subfolder/etc 和 http://www.baidu.com:80/search/info
scheme:URI的模式,如http、file、content等,无scheme则URI无效
host:URI的主机名,比如www.baidu.com,无host则URI无效
path、pathPrefix和pathPattern表示路径信息
如果要为intent指定完整的data,必须调用setDataAndType方法,不能先调用setData再调用setType,因为这两个方法会清除对方已经设置的值,如:intent.setDataAndType(Uri.parse("http://abc"),"video/mpeg");
最后,当我们通过隐式intent启动一个activity时,需要先做一下判断,看是否有activity能够匹配我们的intent,判断的方法有两种:
采用PackageManager的resolveActivity或者Intent的resolveActivity,如果找不到会返回null。如果没有能匹配上的activity并且没有做判断的话,很可能发生ActivityNotFoundException。