应用的三个核心组件:activity,service 和broadcast receiver 都是通过intent来触发的。Intent直译为“意图、意向”。通常也可以理解为不同组件之间通信的“媒介”或者“信使”。Android使用Intent消息机制来实现在相同或者不同应用的组件间在运行时建立联系的方法。 Intent自身数据对象,通常用来描述一个被执行的操作的抽象描述,如打电话,发短信等。接收者如Service/Activity/Broadcase receiver可针对不同的intent进行相应的响应。接收者也就是目标组件可以通过Intent filters来声明自己接收何种Intent。Intent虽然是与组件无关的,也就是说,一个Activity可以申明一个组件,然后使用startActivity传入Intent启动另一个Activity,但是不能用startActivity方法去启动一个Service,只能使用startService方法去启动。这是Android里面的一个限制,避免Intent的调用混乱。

image

3.0.1 Intent 对象

Intent对象需要在不同对象之间传递数据,传递的数据一定是序列化数据,要不然对方也无法进行解析。Android提供了一新的类型接口Parcelable,替换之前的Serializable接口。但是也不是说Serializable不能使用了。为什么提供Parcelable,这是因为Android底层在不同应用或者组件之间进行数据或者消息传递的机制是IBinder。IBinder提供了一个新的封闭容器Parcel。只有实现了Parcelable接口的类才能被放入Parcel中。从这里我们实际上可以看出Parcelable和Serializable进行序列化的区别:

【1】单纯内存操作,从一块内存序列化到另一块内存或者从一个网络对象序列化到另一个网络对象时,Parcelable比Serializable性能高,通常在这种场景下使用Parcelable

【2】需要将数据写入到磁盘时,需要注意,Parcelable类不能保证数据的准确性,建议还是使用Serializable,虽然它还是有一些缺点,但是毕竟是JDK提供的。

以下是Intent的类结构图:

image

从这个类结构图上可以看出Intent实现了Parcelable接口类,因此可以使用IBINDER机制进行消息传递。另外Intent也可以附带一些Parcelable和Serializable数据。

3.0.2 Intent的构成

按照SDK上的表述,一个Intent对象就是一些信息的集合。因为它是一个operation的抽象,因此通常包括接收者需要的action及Data还有Android系统需要的Category.通常一个Intent对象包含六类信息,当然不是每一项都是必须的。需要根据你的应用需要进行设置。如下图所示:

image

我们将从上图显示的六个面一个一个来研究。

【1】ComponentName

ComponetName是一个奇怪的东东,按常理理解,它应该就是接收这个Intent的对应组件。如果简单的处理,其实一个String就可以了,但是在Android里它是一个类,这个类是一个Parcelable。ComponentName类不是必选项,Android也提供了其它的方法来定位接收组件。下图是ComponentName类。

image

创建一个ComponenetName需要给出组件的包名和类名。注意,这里的包名,在文档中未清楚说明。实际上指每个Android应用的基本包名。给定之后,按照SDK的说法,他会创建一个组件的唯一标识。不知道Android内部认为这个唯一标识是什么?也许是独立于类命名空间之外的一个标识。很奇怪的是它也可以从Parcel中获取。下图我们首先创建一个ComponentName,  接着将这个实例传给Intent,然后由Activity启动这个intent.

image

image

接收Activity可以通过Intent取得对应的组件名称与类名。运行结果如下图:

image image

【2】Action

是Intent用来定义需要执行的动作的字符串名。当然一个Action有主动也有被动,比喻在Broadcast中就是一些被动Action,其实被动Action从接收方的角度来说,有点类似于Event的感觉。Android里面对Action,默认定义了一些通用的Action.按照SDK文档中的建议,一个Action,实际上不仅仅是一个参数与返回值的问题,它实际上跟后面的data和extras字段有很多关联。用得好的话,可以带来很多便利。Android鼓励使用缺省的一些Action,不建议过多的自定义的Action。所以反过来,你来看Android缺省的Action它也是一些通用的概念,类似于SDK上描述的一些协议感觉,我觉得未来GOOGLE可能会发展出更抽象的Intent,而不是像现在这样允许用户自定义Action。

Action名称启动组件描述
ACTION_MAINActivity一个任务的主入口,一个应用只能声明一个。没有数据传入也没有返回
ACTION_VIEWActivity用来显示数据,在这个action后面可直接跟上数据源。然后用户通过getData来获取数据,类以于一个查询引擎接口。
ACTION+EDITActivity用来编辑数据,同上面一样,
ACTION_PICKActivity也是用来操作数据,只是先列出一堆数据,供用户选择,如取用户联系人
ACTION_GET_CONTENTActivity同上,但与之区别在于未指定URI,仅仅指定type。
ACTION_INSERTActivity同上,插入数据,指定URI
ACTION_DELETEActivity同上,删除数据,指定URI
ACTION_ATTACH_DATAActivity带一个附件数据
ACTION_CHOOSERActivity与PICK不同的,这个是针对Activity的选择器。
ACTION_PICK_ACTIVITYActivity与Chooser不同,这个只返回一个类,不进入Activity 实例
ACTION_DIALActiivity启动一个打电话的系统自带TASK。
ACTION_CALLActivity与上面的不同,就是这个直接拨打,还有一个前面可以呼叫emergency call number
ACTION_SENDActivity发送一些数据,需要创建chooser
ACTION_SENDTOActivity发送数据,指定URI
ACTION_ANSWERActivity处理一个接收电话
ACTION_RUNActivity计算这个数据
ACTION_SYNCActivity同步数据
ACTION_SEARCHActiivty默认使用GOOGLE seach
ACTION_WEB_SEARCHActivity默认使用GOOGLE seach
ACTION_FACTORY_TESTActivity 

上表是Activity的标准Intent,与Broadcast的Action,有一些是系统发出的Action,你可以执行。但是需要一些权限。下面是自定义Action和系统默认Action的演示。

image

image

下面是运行结果:

image image image

【3】data

正如前述,不同的Action需要结合不同的DATA来一起使用,才能达到你想要的结果。DATA属性就是前述ACTION所需要的数据的URI和MIME类型。因此,设置这个属性时需要根据你的ACTION来决定。这里常用的方法是setData或者setType,因此,这里所说的data属性实际上还包括TYPE属性。下图是一些常见的对应关系:

image

【4】Category

这个属性按照SDK的描述,是指关于接收这个Intent的这种组件的附加信息。因此,它不与普通分类学角度所说的目录。它实际上带有一定的含义的。特别是系统定义的Category,与Action结合,具有特定的含义。是不可以乱用的。按照我的理解,它应该与Android内部对Activity的位置有关,与放在HOME的必须用CATEGORY_HOME,由浏览器打开的用CATEGORY_BROWSABLE。

image

image

image

下面列出一些标准的CATALOGY,这些标准的CATALOGY非常有用,如果用错,对ACTIVIY运行顺序有很大的影响。

CATEGORY 名称描述常量值
CATEGORY_DEFAULTIntent缺省使用的是这个Category,通常如果有多项选择,可以指定一个DEFAULT。但通常由filter来指定android.intent.category.DEFAULT
CATEGORY_BROWSABLE同上一样,通常需要有一个data或者TYPE属性来。这个也通常设置在filter上android.intent.category.BROWSABLE
CATEGORY_TAB主要用于基于Tabactivity内部的不同的Activityandroid.intent.category.TAB
CATEGORY_ALTERNATIVE  
CATEGORY_SELECTED_ALTERNATIVE  
CATEGORY_LAUNCHER  
CATEGORY_INFO  
CATEGORY_HOME  
CATEGORY_PREFERENCE  
CATEGORY_TEST  
CATEGORY_CAR_DOCK  
CATEGORY_DESK_DOCK  
CATEGORY_LE_DESK_DOCK  
CATEGORY_HE_DESK_DOCK  
CATEGORY_CAR_MODE  
CATEGORY_APP_MARKET  

【5】Extras属性

采用键值对的方式向接收组件传递一些附加信息。如启动一个EMAIL,可能直接通过这个属性设置主题和内容就发出去了。那么它与DATA有什么不一样呢?我想这里的关键就在于它是一个附加信息。有没有实际上不影响Intent的启动,但是结果不一样。因为它里面存储的数据是键值数据,因此可以使用Bundle类来存储好,然后放入Extras中。这个属性通常只在intent中使用,不在filter使用,并且SDK为它提供了非常的帮助方法。你可以直接使用。如下图所示,只是一小部分。还有很多。包括GET、SET。

image

下图是一个示例,在前一个Activity中使用extra放入数据,在后一个Activity 中读取数据。

image

image

image image

【6】Flag

指导如何启动一个Activity,用来指明运行的模式,如你希望对方组件需要单独进程运行。你需要设置FLAG_ACTIVITY_NEW_TASK