显式意图示例
显式意图用于启动一个特定的应用程序组件,例如应用程序的某个活动或服务。为了创建一个显式的意图,要为意图对象定义ComponentName
属性,其他的属性都是可选的。
例如,如果在应用程序中创建了一个称作DownloadService
的服务,用来从网络下载文件。可以利用以下代码来启动这个服务:
//这段代码在一个活动内执行,所以活动是Context
//fileUrl是表示URL的字符串,例如
//“http://www.example.com/image.png“
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
构造函数Intent(Contex, Class)
需要应用程序的Context和组件的类对象。这样,活动就通过这个意图启动了应用程序的DownloadService
服务。
隐式意图示例
隐式意图可以通过请求一个动作来启动设备上能够执行这个动作的任何应用程序。隐式意图对于某个动作在你的应用程序不能执行、但是其他应用程序能够执行的情况是非常有用的,它能够让用户选择使用哪个应用程序来执行该动作。
例如,如果希望用户可以和其他用户分享某些内容,可以创建一个具有动作ACTION_SEND
的意图并将其附件设定为要分享的内容。当使用这个意图来调用startActivity()
时,用户通过该意图可选择一个应用程序来分享内容。
注意:如果用户的设备中没有应用程序可以处理传给startActivity()
的隐式意图,那么调用会失败并且应用程序会崩溃。为了确保有活动会接收这个意图,可以调用意图对象的resolveActivity()
。如果结果非空,那么至少有一个应用程序能够处理这个意图,因此调用startActity()
方法是安全的。如果结果为空,那么就不应该使用这个意图并且如果可能的话应该禁用所有会发出这个意图的特性。
//Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType(HTTP.PLAIN_TEXT_TYPE);
if (sendIntent.resolveActivity(getPackageManager()) != null)
{
startActivity(sendIntent);
}
注意:本例中,并没有使用URI,而是通过声明意图的数据类型来指定意图附加的内容。
当startActivity()
被调用时,系统检测所有被安装的应用程序来决定哪些可以处理这类意图(一个请求动作为ACTION_SEND
并携带有“text/plain”数据的意图)。如果只有一个应用程序可以处理这个意图,那么这个应用程序立即启动并接收到这个意图。如果多个活动可接收该意图,那么系统会显示一个对话框让用户选择使用哪个应用程序。
强制显示应用程序选择器
当有多个应用程序能够响应发出的隐式意图时,用户可以选择使用哪个应用程序并且会使该应用程序成为该动作的默认选择。如果用户从此后就一直使用相同的应用来执行这个动作(例如用户总希望由网页浏览器来打开网页),那么这样没有问题。
然而,如果多个应用程序可以响应同一个意图并且用户可能想要每次都使用不同的应用程序,那么应该总是显式地显示一个选择对话框。每一次选择对话框都让用户选择哪个应用程序来执行该动作(用户不能为该动作指定默认应用程序)。例如,当应用程序利用ACTION_SEND
动作执行共享时,用户可能想要依赖于当前的情况使用不同的应用程序来共享,这样就应该总是显示选择对话框,如下图所示。
为了显示对话框选择器,使用createChooser()
方法创建一个意图并将它传递给startActivity()
方法。例如:
Intent intent = new Intent(Intent.ACTION_SEND);
...
//要使用字符串资源来作为UI上的文本
//这里使用的资源文本chooser_title的内容类似于
//"选择应用程序共享此照片"
String title = getResources().getString(R.string.chooser_title);
//创建显示选择器的意图
Intent chooser = Intent.createChooser(intent, title);
//确保这个意图将可以由至少一个活动接收
if (chooser.resolveActivity(getPackageManager()) != null)
{
startActivity(chooser);
}
以上代码将显示一个含有一列可以接收传递给createChooser()方法中的意图的应用程序的对话框,并且使用提供的文本作为对话框标题。
接收隐式意图
为了声明应用程序可以接收哪些隐式意图,在清单文件中使用<intent-filter>
元素为应用程序的每一个组件声明一个或多个意图过滤器。每个意图过滤器基于意图的动作、行为和类别指定组件可以接收的意图类型。只有当隐式意图能够满足某个意图过滤器的要求,系统才会把该意图传递给应用程序。
注意:显式意图总会传递给它的目标,不管目标组件声明的意图过滤器。
应用程序组件应该为它能够做的每一项工作各自声明一个意图过滤器。例如,图库应用程序中的一个活动可能包含两个意图过滤器,一个是查看图片的意图过滤器,一个是编辑图片的意图过滤器。当活动启动时,它查阅意图并基于意图中的信息决定执行哪项任务(例如决定是否显示编辑器控件等)。
每个意图过滤器都是通过应用程序清单文件中的<intent-filter>
元素定义的,这类元素被包含在相应的应用程序的组件元素内(例如<activity>
元素)。在<intent-filter>
中,可以使用以下三个元素来指定接收意图的类型:
<action>
。 在其name
属性中,声明接收的意图动作。为name
属性指定的值必须是动作的字符串常量值,而不是类常量。<data>
。使用指定数据URI
和MIME
类型的多个方面的一个或属性来声明接收的数据的类型。<category>
。在其name
属性中声明接收的意图类别。值必须是一个动作的字符串常量值,而不是类常量。
注意:为了接收隐式意图,必须在意图过滤器里包含CATEGORY_DEFAULT
类别。方法startActivity()
和startActivityForResult()
都假定所有的意图声明为CATEGORY_DEFAULT
类别。如果不在意图过滤器中声明这个类别,就没有隐式过滤器会发送到这个活动。
例如,下面是一个通过意图过滤器声明接收ACTION_SEND
意图的活动,且它接收的意图的数据类型为文本。
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
一个过滤器可以包含多个<action>
、<data>
和<category>
元素。如果这么做,那么这个组件就必须能够处理这些过滤器元素的任何组合。
当想要处理多类意图但又要求只是特定的动作、数据和类别的组合时,可以创建多个意图过滤器。
隐式意图通过比较意图过滤器中的三个元素进行测试。为了能够传递给该组件,意图必须经过所有的三个测试。如果不能满足任何一个测试,Android
系统就不会将意图传递给这个组件。然而,由于一个组件可能包含多个意图过滤器,没有通过其中一个意图过滤器检测的意图可能通过另一个意图过滤器的检测。
小心:为了避免无意地运行一个不同应用程序的服务,请总是使用显式意图来启动自己的服务,而不是为服务声明隐式意图。
注意:对于所有的活动,必须在清单文件中声明意图过滤器。然而,对于广播接收者来说,过滤器可以通过调用 registerReceiver()
动态注册。可以通过unRegisterReceiver()
取消注册。这样做可以让应用程序只在应用程序运行的特定时期监听特定的广播。