在Android中,应用组件也是通过Intent来激活的,其中内容提供器是通过ContentResolver发出请求的方式来激活的,而Activity、服务和广播接收器则是通过所谓的Intent异步消息的方式来激活的。
利用Intent激活组件的操作方法有:startActivity(Intent)、startService(Intent)、bindService(Intent, ServiceConnection, int)、sendBroadcast(Intent)等,其中 startActivity()方法用于发起Activity,startService()方法用于发起服务,bindService()方法用于绑定服务,而 sendBroadcast()方法则用来向所有关联的广播接收器发送广播。
为了能收到Intent消息,AndroidManifest.xml 的“intent-filter”元素必须包含至少一个“action”元素,否则Intent过滤器会过滤掉所有的Intent消息。
在通信过程中,Intent负责对通信消息进行描述,Android则根据Intent的描述,找到匹配的组件,将 Intent传递给匹配的组件,并完成组件的调用。如在文件管理器中,为了打开一个文件,相应Intent的实现如下:
Intent activityIntent = new Intent(Intent.ACTION_VIEW);
activityIntent.setDataAndType(path, mimetype);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activityIntent);
如果实在希望了解是否有匹配的组件存在,可以做如下的判断:
public static boolean isRecognizedFileType(Context context, Uri fileUri, String mimetype)
{
boolean ret = true;
if (D) Log.d(TAG, "RecognizedFileType() fileUri: " + fileUri + " mimetype: " +
mimetype);
Intent mimetypeIntent = new Intent(Intent.ACTION_VIEW);
mimetypeIntent.setDataAndType(fileUri, mimetype);
List< ResolveInfo> list = context.getPackageManager().queryIntentActivities(mimetypeIntent,PackageManager.
MATCH_DEFAULT_ONLY);
if (list.size() == 0)
{
if (D) Log.d(TAG, "NO application to handle MIME type " + mimetype);
ret = false;
}
return ret;
}
因此,Intent在通信过程中起着媒介的作用,专门传递组件互相调用的相关信息,实现了调用者与被调用者之间的解耦。
在Android中,Intent携带的信息主要有两种属性:行为(Action)和数据(Data)。其他属性还有类别(Category)、数据类型(Type)、组件(Component)、附加信息(extras)等。
·“Action”属性是对所执行消息主旨的描述,对常见的Action,如查看、编辑、拨号等,Android在系统层面进行了定义,如DIAL_ACTION、MAIN_ACTION、 VIEW_ACTION、EDIT_ACTION。对特殊的行为,允许开发者自定义。
·“Data”属性即所执行消息涉及的数据,在Android中采用指向数据的URI来表示。如content://contacts/people/1,意思为电话簿中标识符为“1”的条目信息。
·“Category”属性即所执行消息的附加信息。例如,LAUNCHER_CATEGORY 表示Intent 的目标Activity应该作为应用主界面出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选行为中的一个,这些行为可以在同一块数据上执行。
·“Type”属性显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置“Type”属性,可以显示指定数据类型。
·“Component”属性指定Intent的目标组件的类名。通常 Android会根据Intent 中包含的其他属性的信息,如Action、Sata、Type、Category等属性进行解析,终找到一个与之匹配的目标组件。但是如果指定“Component”属性,将直接使用其指定的组件,而不再执行上述解析过程。指定该属性后,Intent的其他所有属性均变为可选属性。该属性在Activity的相互调用中经常使用。
·“extras”属性是其他所有附加信息的集合。使用“extras”属性可以为组件提供扩展信息,比如如果要执行“发送电子邮件”,可以将电子邮件的标题、正文等保存在“extras”属性里,传给电子邮件发送组件。这给程序开发带来了较强的灵活性。该属性在传递数据时经常使用。
在Android中,根据是否声明“Component”属性的不同,Intent可以分为显式Intent和隐式Intent两种。
其中显式Intent即指定了“Component”属性的Intent(代码实现为通过调用setComponent()方法或setClass()方法)。通过指定具体的组件类,通知应用启动对应的组件。
隐式Intent即没有指定“Component”属性的Intent。这类Intent需要包含足够的信息,这样系统才能根据这些信息,在所有的可用组件中,解析出匹配此Intent的组件。
对于显式Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些隐式Intent,通过解析,将 Intent传递给匹配此Intent的Activity、IntentReceiver或服务。实际的Activity的解析是通过resolveActivity()进行的。
Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有Intent过滤器及其中定义的 Intent,终找到匹配的组件。在解析过程中,Android依赖于Intent的Action、Type、Category等属性,解析策略如下:
·如果Intent声明“Action”属性,则目标组件的Intent过滤器的Action列表中就必须包含该Action,否则不能匹配。
·如果Intent没有声明“Type”属性,系统将从“Data”属性中得到数据的类型。和Action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。
·如果Intent中的“Data”属性不是“content:”类型的URI,且没有声明“Type”属性,系统将根据Intent中数据的协议类型(scheme,如http:、mailto:)进行匹配。同上,Intent 的协议类型必须出现在目标组件的协议类型列表中。
·如果Intent为“Category”属性赋予了多个类别值,这些类别必须全部出现在组件的类别列表中。假如Intent中包含了两个类别:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。
当希望能够对一个外部的事件(来电、电量发生变化等)做出响应时,开发者需要注册一个Intent过滤器。Intent接收器在关联的事件发生时,会通知应用收到的事件,各种应用还可以通过使用Context.broadcastIntent()方法将Intent 消息广播给其他应用程序。
Intent过滤器可以在AndroidManifest.xml中注册,如为了接收打开相应类型的音频文件的请求,相应的Intent过滤器如下:
< intent-filter>
< action android:name="android.intent.action.VIEW" />
< category android:name="android.intent.category.DEFAULT" />
< data android:scheme="content"/>
< data android:host="media"/>
< data android:mimeType="audio/*"/>
< data android:mimeType="application/ogg"/>
< data android:mimeType="application/x-ogg"/>
< data android:mimeType="application/itunes"/>
< /intent-filter>
部分开发者可能搞不明白MIME类型的含义,有时可能自我想象的确定MIME类型,殊不知MIME类型是有规范的,对于每一种文件类型,其标识符唯一。
Intent的标志位主要有FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_ CLEAR_TOP、FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 、FLAG_ACTIVITY_SINGLE_ TOP等,这些标志位的详细含义可以参考Android的帮助文档。