Android组件间的交互和进程间IPC通信

在Android中窗体与窗体之间如何互相调用和交换数据?窗体(Activity)和后台的服务(Service)如何通信?基于 Unix(Linux )的系统都有一个很优秀的传统,就是倡导非常轻便的进程间通信(IPC)机制;倡导进程通过IPC来互相协作;倡导功能单一,小巧而强壮的进程,而不是又大又复杂的“万金油”。同样,在Android中我们可以将我们的Activity和Service放在不同的进程中运行,我们可以在我们的Task 中加载其他进程的Activity,这些机制都鼓励我们“尽量利用已有的功能,利用IPC和包含这些已有功能的程序协作,来完成一个完整的应用”,例如在我们的程序中充分利用Google Map的相关窗体和服务。所有这些都建立在一套轻便好用的IPC机制上。

  Android的组件和进程间通信都建立在一种基于称为Intent的消息基础之上。Intent就是一种消息,它包含了两个重要的内容:1. 消息的目的,即这个消息是发给哪个组件的?(消息的目的中不会包含“消息是发给哪个进程”这样的信息,这里Android有意淡化进程的概念,而只让我们关心组件,因为了解太多关于进程的具体信息会加大复杂度,而又如何做到进程间的消息传递呢?下文会说到一种Android中关于这点比较特别的设计方式,我认为是一种简捷有用又符合手机特点的设计);2. 消息所携带的数据内容,即需要传递给目标的数据。下面是一个简单的利用Intent来启动一个Service并向其传递数据的代码示例:

  Intent serviceIntent = new Intent(context, svrMain.class);

  serviceIntent.putExtra(“Network_Report”, networkStatus);

  context.startService(serviceIntent);

  上面的代码首先构造了一个Intent对象,并在构造的时候指定了这个Intent的目的地,即“svrMain.class”,表示这个Intent是要传递给一个类名叫svrMain的Service。然后向这个Intent中放入了一个数据,数据的key为 “Network_Report”,value为一个叫networkStatus的int类型变量,用来指明当前网络的状态。最后我们使用系统提供的上下文API,将这个Intent传递给指定的Service。

  Intent的消息目的地分为两种模式,一种是显式的,一种是隐式的。我们上面的例子中看到的就是一个显式消息的例子。显式消息直接指定消息目的地组件的类元信息,例如上面例子中svrMain就是我们写的一个类名为svrMain的Service,class操作符就是获取其类元信息。这种模式的消息由于已经确切知道了消息目标的确切信息,所以只适用于同一进程内的不同组件之间通信,例如打开一个子窗体,和同一进程中的service通信等。对应的,隐式消息就一般用于跨进程的通信了,隐式消息没有确定的消息目的地,除了数据外,隐式消息只是包含了一些用于表征消息特征的描述字段。而一些需要收到某种特定特征消息的某个程序中的某个组件,需要通过在其所在程序的AndroidMainifest.xml中注册一种被称为intent-filter的消息特征筛选器,然后Android系统会按照一定的匹配规则来匹配发出的消息特征和所有拥有响应这种特征的intent-filter的组件(无论是同一进程内的组件还是不同程序中的组件),匹配到的组件就会接受到相应的消息。前面的描述多少有些拗口,我们举个实际的例子来说明,如果我们想开启一个子窗体(无论这个窗体来自同一进程还是不同进程),我们除了使用显式消息外,我们还可以使用隐式消息:

Intent openSomeDiagIntent = new Intent();

  openSomeDiagIntent.setAction(“edwin.demo.fooActivity”);

  this.startActivity(openSomeDiagIntent);

  上面的隐式消息不包含具体的目的地,而是仅包含一个名位“Action”的特征字符串,Action就是上文所说的Intent特征的一种。从字面上来理解,可以理解为这个消息所代表的是完成某一个动作的含义,由action来标明动作的名字。所有能够处理这种动作的Activity都可以收到该消息。对应的,可能在同一个程序或者另外的某个程序的AndroidMainifest.xml中声明了下面这样的一个Activity:

  < activity android:name=”.fooActivity”>

  < intent-filter>

  < action android:name=”edwin.demo.fooActivity” />

  < /intent-filter>

  < /activity>

  那么这就表示这个Activity能够收到并处理action为“edwin.demo.fooActivity”的消息。所以上面的代码串起来的效果就是,打开了这个名为.fooActivity的窗口,无论这个窗口是在当前的进程中还是另外的一个程序中。

  除了Action这种消息特征外,Intent还有category,data这两个特征描述属性。Category同样是一个字符串,从字面上理解就是 “消息的分类特征”。从程序上看其和Action的不同在于,一个Intent只能有惟一的一个Action名称,但是却可以包含多个Category字符串;一个Intent-Filter可以包含多个Action节点但至少要包含一个,另一方面一个Intent-Filter可以包含零到多个 Category节点。Android在做Intent-Filter匹配的时候,Intent的Action属性匹配到Intent-Filter中的任何一个action节点,就表明拥有这个Intent-Filter的组件能够处理这种消息;而对于Category来讲一个Intent中的所有的 Category都必须存在于Intent-Filter中的Category节点中时,才表明匹配成功。Data属性可以描述一个Intent所要传递的数据类型和URI,每一个Intent只能包含一个Data属性。其中数据的类型使用MIME类型描述方式来描述,例如video/mpeg表示编码格式为mpeg的视频,这里也可以使用通配符,例如video/*表示任意格式的视频文件类型;数据的URI由scheme(协议),host,port,path四部分组成:scheme://host:port/path,例如http://test.com:8080 /file/file1 或者content://edwin.demo.contentProvider:100/forder/content1,其中path部分也是可以支持通配符的。Data属性是一个很有用的描述特征,例如下面这样的一个包含data节点的Intent-Filter:

  <activity android:name=”.actHttpVideoMan”>


<intent-filter>
  <action android:name=”edwin.demo.actHttpVideoMan.Main” />
  <data android:scheme=”http” android:type=”video/*” />
  </intent-filter>
  </activity>
  它表示窗体actHttpVideoMan能够处理来自web服务器的视频文件。这样的filter有什么作用呢?最典型的情况就是配合浏览器工作。浏览器在打开一个链接的时候首先会尝试显示这个链接对应的html页面,如果这个链接不是一个html页面,而是一个视频文件或者其他浏览器本身不能处理的格式的话,浏览器会使用隐式消息尝试开启一个能够处理这种数据格式的Activity来处理,浏览器发出的隐式消息就是一个包含data属性,其中URI scheme为http,数据类型为video/*的消息,如果有能够匹配这个intent的组件,例如我们上面的那个activity,浏览器就会启动这个窗体,接着这个窗体会根据data属性指定的URI去播放在线视频,如果没有可以处理这个intent的Activity,浏览器才会调用下载管理器下载文件。

  隐式消息这个设计简单有效,它忽略了进程的细节,让IPC在一个更高的更接近人脑思维模式的层次工作,让系统中的不同进程协作看起来就像是同一程序中的协作一样,这种简单的IPC机制在很大的程度上鼓励我们和其他进程协作,通过协作的进程来完成一个复杂的任务,而不是把什么功能都做到一个大而全的程序里面。不过上文还有一些细节没有提到,例如如果一个intent有多个可匹配的处理组件,系统如何处理?这就要分响应消息的组件类型来说了,如果是 service,那么这些service都可以启动并处理消息,如果是Activity,则android会弹出一个对话框让用户进行选择。比如我们安装了多个可以处理在线视频的软件,当我们在浏览器中点击一个在线视频的链接时,系统会让用户选择使用哪个软件来观看。另外大家一定会想到安全性的问题,如果不同进程间的组件可以通过隐式消息互相通信,那我们的程序不是可以轻易调用到其他的程序或者系统中的一些敏感程序的组件,这样会不会很不安全呢?其实 Android在安全方面有一个统一,完备和轻便的安全策略模型,Intent的安全自然是被考虑在内的,关于android的安全模型我会在后续的系列 blog中专门说明。

  最后,除了Intent这种基于消息的进程内和进程间通信模型外,android中也有一种相比起来稍显笨重一些的IPC机制,它采用类似远程方法调用的方案,通过接口定义文件AIDL来定义一个IPC接口,然后通过接收方实现接口,调用方调用接口的本地代理实现来完成IPC。这种模型只适用于Activity和Service间的通信,之所以需要这种稍显重量的模式,是因为Activity除了发送intent去启动一个service外,可能还需要能够在Service的运行过程中连接到service,对Service发送一些控制请求。例如音乐播放程序,其后台的播放服务往往独立运行,以方便我们在使用其他程序界面时也能听到音乐。同时这个后台播放服务也会定义一个控制接口,包含比如播放,暂停,快进之类的方法,任何时候播放程序的界面都可以通过使用bindService API连接到播放服务,获取这个接口的包含IPC细节的实现代理,通过这组控制接口方法对其进行控制,这时这种IPC的方案就显的更方便更直观一些了。有关使用AIDL这种IPC的更详细描述, google的官方文档="">已做了详细的讲解。


大部分移动设备平台上的应用程序都运行在他们自己的沙盒中。他们彼此之间互相隔离,并且严格限制应用程序与硬件和原始组件之间的交互。 我们知道交流是多么的重要,作为一个孤岛没有交流的东西,一定毫无意义!Android应用程序也是一个沙盒,但是他们能够使用Intent、Broadcast Receivers、Adapters、Content Providers、Internet去突破他们的边界互相交流。有交流还会和谐,由此可见这些交流手段有多重要。

上篇文章中我们在SMS接收程序和使用Intent发送SMS程序中用到了Intent,并做了简单的回顾和总结:android应用程序的三大组件——Activities、Services、Broadcast Receiver,通过消息触发,这个消息就称作意图(Intent)。然后以活动为例简单介绍了Intent了并说明Intent机制的好处。既然在SMS程序中用到了Intent,这里我就借机顺着这条线,彻底详细地介绍一下Intent。分两篇文章介绍:

Android开发之旅: Intents和Intent Filters(理论部分)
Android开发之旅: Intents和Intent Filters(实例部分)
本文的主要内容如下:

1、概述
2、Intent对象
2.1、组件名字
2.2、动作
2.3、数据
2.4、种类
2.5、附加信息
2.6、标志
3、Intent解析
3.1、Intent过滤器
3.1.1、动作检测
3.1.2、种类检测
3.1.3、数据检测
3.2、通用情况
3.3、使用intent匹配
1、概述
一个应用程序的三个核心组件——activities、services、broadcast receivers,都是通过叫做intents的消息激活。Intent消息是一种同一或不同应用程序中的组件之间延迟运行时绑定的机制。intent本身(是一个Intent对象),是一个被动的数据结构保存一个将要执行的操作的抽象描述,或在广播的情况下,通常是某事已经发生且正在宣告。对于这三种组件,有独立的传送intent的机制:

Activity:一个intent对象传递给Context.startActivity()或Activity.startActivityForRestult()去启动一个活动或使一个已存在的活动去做新的事情。
Service:一个intent对象传递给Context.startService()去初始化一个service或传递一个新的指令给正在运行的service。类似的,一个intent可以传递给Context.bindService()去建立调用组件和目标服务之间的连接。
Broadcast Receiver:一个intent对象传递给任何广播方法(如Context.sendBroadcast(),Context.sendOrderedBroadcast(),Context.sendStickyBroadcast()),都将传递到所有感兴趣的广播接收者。
在每种情况下,Android系统查找合适的activity、service、broadcast receivers来响应意图,如果有必要的话,初始化他们。这些消息系统之间没有重叠,即广播意图仅会传递给广播接收者,而不会传递活动或服务,反之亦然。

下面首先描述intent对象,然后介绍Android将intent映射到相应组件的规则——如何解决哪个组件应该接收intent消息。对于没有指定目标组件名字的intent,这个处理过程包括按照intent filters匹配每个潜在的目标对象。

2、Intent对象
一个Intent对象是一个捆信息,包含对intent有兴趣的组件的信息(如要执行的动作和要作用的数据)、Android系统有兴趣的信息(如处理intent组件的分类信息和如何启动目标活动的指令)。下面列出它的主要信息:

2.1、组件名字
处理intent的组件的名字。这个字段是一个ComponentName对象——是目标组件的完全限定类名(如"com.example.project.app.FreneticActivity")和应用程序所在的包在清单文件中的名字(如"com.example.project")的组合。其中组件名字中的包部分不必一定和清单文件中的包名一样。

组件名字是可选的,如果设置了,intent对象传递到指定类的实例;如果没有设置,Android使用intent中的其它信息来定位合适的目标组件(见下面的Intent解析)。组件的名字通过setComponent(),setClass()或setClassName()设置,通过getComponent()读取。

2.2、动作
一个字符串命名的动作将被执行,或在广播intent中,已发生动作且正被报告。Intent类定义了一些动作常量,如下:

Constant
Target component
Action

ACTION_CALL
activity
Initiate a phone call.

ACTION_EDIT
activity
Display data for the user to edit.

ACTION_MAIN
activity
Start up as the initial activity of a task, with no data input and no returned output.

ACTION_SYNC
activity
Synchronize data on a server with data on the mobile device.

ACTION_BATTERY_LOW
broadcast receiver
A warning that the battery is low.

ACTION_HEADSET_PLUG
broadcast receiver
A headset has been plugged into the device, or unplugged from it.

ACTION_SCREEN_ON
broadcast receiver
The screen has been turned on.

ACTION_TIMEZONE_CHANGED
broadcast receiver
The setting for the time zone has changed.


查看更多的动作请参考Intent类。其它的动作定义在Android API中,我们还可以定义自己的动作字符串一再我们的应用程序中激活组件。自定义动作字符串应该包含应用程序报名前缀,如"com.example.project.SHOW_COLOR"。

动作很大程度上决定了剩下的intent如何构建,特别是数据(data)和附加(extras)字段,就像一个方法名决定了参数和返回值。正是这个原因,应该尽可能明确指定动作,并紧密关联到其它intent字段。换句话说,应该定义你的组件能够处理的Intent对象的整个协议,而不仅仅是单独地定义一个动作。

一个intent对象的动作通过setAction()方法设置,通过getAction()方法读取。

2.3、数据
数据(data)是将作用于其上的数据的URI和数据的MIME类型。不同的动作有不同的数据规格。例如,如果动作字段是ACTION_EDIT,数据字段将包含将显示用于编辑的文档的URI;如果动作是ACTION_CALL,数据字段将是一个tel:URI和将拨打的号码;如果动作是ACTION_VIEW,数据字段是一个http:URI,接收活动将被调用去下载和显示URI指向的数据。

当匹配一个intent到一个能够处理数据的组件,通常知道数据的类型(它的MIME类型)和它的URI很重要。例如,一个组件能够显示图像数据,不应该被调用去播放一个音频文件。

在许多情况下,数据类型能够从URI中推测,特别是content:URIs,它表示位于设备上的数据且被内容提供者(content provider)控制。但是类型也能够显示地设置,setData()方法指定数据的URI,setType()指定MIME类型,setDataAndType()指定数据的URI和MIME类型。通过getData()读取URI,getType()读取类型。

2.4、种类
此外,还包含关于应该处理intent的组件类型信息。可以在一个Intent对象中指定任意数量的种类描述。Intent类定义的一些种类常量,如下这些:

Constant
Meaning

CATEGORY_BROWSABLE
The target activity can be safely invoked by the browser to display data referenced by a link — for example, an image or an e-mail message.

CATEGORY_GADGET
The activity can be embedded inside of another activity that hosts gadgets.

CATEGORY_HOME
The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed.

CATEGORY_LAUNCHER
The activity can be the initial activity of a task and is listed in the top-level application launcher.

CATEGORY_PREFERENCE
The target activity is a preference panel.


更多的种类常量请参考Intent类。

addCategory()方法添加一个种类到Intent对象中,removeCategory()方法删除一个之前添加的种类,getCategories()方法获取Intent对象中的所有种类。

2.5、附加信息
额外的键值对信息应该传递到组件处理intent。就像动作关联的特定种类的数据URIs,也关联到某些特定的附加信息。例如,一个ACTION_TIMEZONE_CHANGE intent有一个"time-zone"的附加信息,标识新的时区,ACTION_HEADSET_PLUG有一个"state"附加信息,标识头部现在是否塞满或未塞满;有一个"name"附加信息,标识头部的类型。如果你自定义了一个SHOW_COLOR动作,颜色值将可以设置在附加的键值对中。

Intent对象有一系列的put…()方法用于插入各种附加数据和一系列的get…()用于读取数据。这些方法与Bundle对象的方法类似,实际上,附加信息可以作为一个Bundle使用putExtras()和getExtras()安装和读取。

2.6、标志
有各种各样的标志,许多指示Android系统如何去启动一个活动(例如,活动应该属于那个任务)和启动之后如何对待它(例如,它是否属于最近的活动列表)。所有这些标志都定义在Intent类中。

3、Intent解析
Intent可以分为两组:

显式intent:通过名字指定目标组件。因为开发者通常不知道其它应用程序的组件名字,显式intent通常用于应用程序内部消息,如一个活动启动从属的服务或启动一个姐妹活动。
隐式intent:并不指定目标的名字(组件名字字段是空的)。隐式intent经常用于激活其它应用程序中的组件。
Android传递一个显式intent到一个指定目标类的实例。Intent对象中只用组件名字内容去决定哪个组件应该获得这个intent,而不用其他内容。

隐式intent需要另外一种不同的策略。由于缺省指定目标,Android系统必须查找一个最适合的组件(一些组件)去处理intent——一个活动或服务去执行请求动作,或一组广播接收者去响应广播声明。这是通过比较Intent对象的内容和intent过滤器(intent filters)来完成的。intent过滤器关联到潜在的接收intent的组件。过滤器声明组件的能力和界定它能处理的intents,它们打开组件接收声明的intent类型的隐式intents。如果一个组件没有任何intent过滤器,它仅能接收显示的intents,而声明了intent过滤器的组件可以接收显示和隐式的intents。

只有当一个Intent对象的下面三个方面都符合一个intent过滤器:action、data(包括URI和数据类型)、category,才被考虑。附加信息和标志在解析哪个组件接收intent中不起作用。

3.1、Intent过滤器
活动、服务、广播接收者为了告知系统能够处理哪些隐式intent,它们可以有一个或多个intent过滤器。每个过滤器描述组件的一种能力,即乐意接收的一组intent。实际上,它筛掉不想要的intents,也仅仅是不想要的隐式intents。一个显式intent总是能够传递到它的目标组件,不管它包含什么;不考虑过滤器。但是一个隐式intent,仅当它能够通过组件的过滤器之一才能够传递给它。

一个组件的能够做的每一工作有独立的过滤器。例如,记事本中的NoteEditer活动有两个过滤器,一个是启动一个指定的记录,用户可以查看和编辑;另一个是启动一个新的、空的记录,用户能够填充并保存。

一个intent过滤器是一个IntentFilter类的实例。因为Android系统在启动一个组件之前必须知道它的能力,但是intent过滤器通常不在java代码中设置,而是在应用程序的清单文件(AndroidManifest.xml)中以<intent-filter>元素设置。但有一个例外,广播接收者的过滤器通过调用Context.registerReceiver()动态地注册,它直接创建一个IntentFilter对象。

一个过滤器有对应于Intent对象的动作、数据、种类的字段。过滤器要检测隐式intent的所有这三个字段,其中任何一个失败,Android系统都不会传递intent给组件。然而,因为一个组件可以有多个intent过滤器,一个intent通不过组件的过滤器检测,其它的过滤器可能通过检测。

3.1.1、动作检测
清单文件中的<intent-filter>元素以<action>子元素列出动作,例如:

<intent-filter . . . >
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
. . .
</intent-filter>像例子所展示,虽然一个Intent对象仅是单个动作,但是一个过滤器可以列出不止一个。这个列表不能够为空,一个过滤器必须至少包含一个<action>子元素,否则它将阻塞所有的intents。

要通过检测,Intent对象中指定的动作必须匹配过滤器的动作列表中的一个。如果对象或过滤器没有指定一个动作,结果将如下:

如果过滤器没有指定动作,没有一个Intent将匹配,所有的intent将检测失败,即没有intent能够通过过滤器。
如果Intent对象没有指定动作,将自动通过检查(只要过滤器至少有一个过滤器,否则就是上面的情况了)
3.1.2、种类检测
类似的,清单文件中的<intent-filter>元素以<category>子元素列出种类,例如:

<intent-filter . . . >
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
. . .
</intent-filter>注意本文前面两个表格列举的动作和种类常量不在清单文件中使用,而是使用全字符串值。例如,例子中所示的"android.intent.category.BROWSABLE"字符串对应于本文前面提到的BROWSABLE常量。类似的,"android.intent.action.EDIT"字符串对应于ACTION_EDIT常量。

对于一个intent要通过种类检测,intent对象中的每个种类必须匹配过滤器中的一个。即过滤器能够列出额外的种类,但是intent对象中的种类都必须能够在过滤器中找到,只有一个种类在过滤器列表中没有,就算种类检测失败!

因此,原则上如果一个intent对象中没有种类(即种类字段为空)应该总是通过种类测试,而不管过滤器中有什么种类。但是有个例外,Android对待所有传递给Context.startActivity()的隐式intent好像它们至少包含"android.intent.category.DEFAULT"(对应CATEGORY_DEFAULT常量)。因此,活动想要接收隐式intent必须要在intent过滤器中包含"android.intent.category.DEFAULT"。

注意:"android.intent.action.MAIN" 和 "android.intent.category.LAUNCHER"设置,它们分别标记活动开始新的任务和带到启动列表界面。它们可以包含"android.intent.category.DEFAULT"到种类列表,也可以不包含。

3.1.3、数据检测
类似的,清单文件中的<intent-filter>元素以<data>子元素列出数据,例如:

<intent-filter . . . >
<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:mimeType="audio/mpeg" android:scheme="http" . . . />
. . .
</intent-filter>每个<data>元素指定一个URI和数据类型(MIME类型)。它有四个属性scheme、host、port、path对应于URI的每个部分:
scheme://host:port/path
例如,下面的URI:
content://com.example.project:200/folder/subfolder/etc
scheme是content,host是"com.example.project",port是200,path是"folder/subfolder/etc"。host和port一起构成URI的凭据(authority),如果host没有指定,port也被忽略。 这四个属性都是可选的,但它们之间并不都是完全独立的。要让authority有意义,scheme必须也要指定。要让path有意义,scheme和authority也都必须要指定。

当比较intent对象和过滤器的URI时,仅仅比较过滤器中出现的URI属性。例如,如果一个过滤器仅指定了scheme,所有有此scheme的URIs都匹配过滤器;如果一个过滤器指定了scheme和authority,但没有指定path,所有匹配scheme和authority的URIs都通过检测,而不管它们的path;如果四个属性都指定了,要都匹配才能算是匹配。然而,过滤器中的path可以包含通配符来要求匹配path中的一部分。

<data>元素的type属性指定数据的MIME类型。Intent对象和过滤器都可以用"*"通配符匹配子类型字段,例如"text/*","audio/*"表示任何子类型。

数据检测既要检测URI,也要检测数据类型。规则如下:

一个Intent对象既不包含URI,也不包含数据类型:仅当过滤器也不指定任何URIs和数据类型时,才不能通过检测;否则都能通过。
一个Intent对象包含URI,但不包含数据类型:仅当过滤器也不指定数据类型,同时它们的URI匹配,才能通过检测。例如,mailto:和tel:都不指定实际数据。
一个Intent对象包含数据类型,但不包含URI:仅当过滤也只包含数据类型且与Intent相同,才通过检测。
一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出):数据类型部分,只有与过滤器中之一匹配才算通过;URI部分,它的URI要出现在过滤器中,或者它有content:或file: URI,又或者过滤器没有指定URI。换句话说,如果它的过滤器仅列出了数据类型,组件假定支持content:和file: 。
如果一个Intent能够通过不止一个活动或服务的过滤器,用户可能会被问那个组件被激活。如果没有目标找到,会产生一个异常。

3.2、通用情况
上面最后一条规则表明组件能够从文件或内容提供者获取本地数据。因此,它们的过滤器仅列出数据类型且不必明确指出content:和file: scheme的名字。这是一种典型的情况,一个<data>元素像下面这样:

<data android:mimeType="image/*" />告诉Android这个组件能够从内容提供者获取image数据并显示它。因为大部分可用数据由内容提供者(content provider)分发,过滤器指定一个数据类型但没有指定URI或许最通用。

另一种通用配置是过滤器指定一个scheme和一个数据类型。例如,一个<data>元素像下面这样:

<data android:scheme="http" android:type="video/*" />告诉Android这个组件能够从网络获取视频数据并显示它。考虑,当用户点击一个web页面上的link,浏览器应用程序会做什么?它首先会试图去显示数据(如果link是一个HTML页面,就能显示)。如果它不能显示数据,它将把一个隐式Intent加到scheme和数据类型,去启动一个能够做此工作的活动。如果没有接收者,它将请求下载管理者去下载数据。这将在内容提供者的控制下完成,因此一个潜在的大活动池(他们的过滤器仅有数据类型)能够响应。

大部分应用程序能启动新的活动,而不引用任何特别的数据。活动有指定"android.intent.action.MAIN"的动作的过滤器,能够启动应用程序。如果它们出现在应用程序启动列表中,它们也指定"android.intent.category.LAUNCHER"种类:

<intent-filter . . . >
<action android:name="code android.intent.action.MAIN" />
<category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>3.3、使用intent匹配
Intents对照着Intent过滤器匹配,不仅去发现一个目标组件去激活,而且去发现设备上的组件的其他信息。例如,Android系统填充应用程序启动列表,最高层屏幕显示用户能够启动的应用程序:是通过查找所有的包含指定了"android.intent.action.MAIN"的动作和"android.intent.category.LAUNCHER"种类的过滤器的活动,然后在启动列表中显示这些活动的图标和标签。类似的,它通过查找有"android.intent.category.HOME"过滤器的活动发掘主菜单。

我们的应用程序也可以类似的使用这种Intent匹配方式。PackageManager有一组query…()方法返回能够接收特定intent的所有组件,一组resolve…()方法决定最适合的组件响应intent。例如,queryIntentActivities()返回一组能够给执行指定的intent参数的所有活动,类似的queryIntentServices()返回一组服务。这两个方法都不激活组件,它们仅列出所有能够响应的组件。对应广播接收者也有类似的方法——queryBroadcastReceivers()。

注:本文的主要内容意译自SDK文档。抱歉此系列的发文速度越来越来,主要是因为现在空闲时间很少,每天下班之后除了要写此系列的文章,还有其它知识需要总结并且还有为每天的工作做知识准备(大家应该也发现了我的blog最近发布了一些关于C++的文章)。其实我一直告诫自己,信息时代效率是关键(当然专注作为一种品质,任何时候都非常重要),如果效率一直这么低而且不够专注,将来Android 2.2、2.3甚至更高版本都发布了,我这系列的基础部分都还没有写完。我会尽量加快此系列的发文速度,当然我会保持一贯的作风——文章的内容要经过验证才会发布,尽可能保证内容的正确性,不过由于一个人的见识和天生的会陷入自我思维,错误在所难免!还希望大家及时指出,以免文章误导他人和让我一直错下去。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值