Intent对象可以向操作系统描述我们需要处理的任务。使用显式intent,我们需明确地告诉操作系统要启动的activity类名。
下面是之前创建过的显式intent:
Intent i = new intent(Context packageContext, Class<?> cls);
startActivity(i);
而使用隐式intent,只需向操作系统描述清楚我们的工作意图。操作系统会去启动那些对外宣称能够胜任工作任务的activity。如果操作系统找到多个符合的activity,用户将会看到一个可选应用列表,然后就看用户如何选择了。
隐式intents并不声明要启动组件的具体类名,而是声明一个需要执行的action。这个action指定了我们想做的事情,例如查看,编辑,发送或者是获取一些东西。
Intents通常会在发送action的同时附带一些数据,例如你想要查看的地址或者是你想要发送的邮件信息。
数据的具体类型取决于我们想要创建的Intent,比如Uri或其他规定的数据类型,或者甚至也可能根本不需要数据。
下面是一个隐式intent的主要组成部分,可以用来定义我们的工作任务。
通常以Intent类中的常量来表示。
例如,要访问查看某个URL,可以使用Intent.ACTION_VIEW;
要发送邮件,可以使用Intent.ACTION_SEND。
例如,查看网页:
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
这可能是设备以外的资源,如某个网页的URL,也可能是指向某个文件的URI,或者是指向ContentProvider中某条记录的某个内容URI(content URI)。
如果数据是一个Uri,会有一个简单的Intent() 构造方法 用于定义action与data。
例如,下面是一个带有指定电话号码的intent:
Uri number = Uri.parse("tel:1234567");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
这指的是MIME形式的数据类型,如text/html或audio/mpeg3。
如果一个intent包含某类数据的位置,那么通常可以从中推测出数据的mime类型。
如果操作用于描述具体要做什么,那么类别通常用来描述我们是何时、何地或者说如何使用某个activity的。
可以使用 addCategory()
指定类别。
Android的android.intent.category.LAUNCHER类别表明,activity应该显示在顶级应用启动器中。
而android.intent.category.INFO类别表明,虽然activity向用户显示了包信息,但它不应该显示在启动器中。
基于以上信息,操作系统将启动适用应用的适用activity(如果有多个适用应用可选,用户可自行如何选择)。
通过配置文件中的intent过滤器设置,activity会对外宣称自己是适合处理ACTION_VIEW的activity。
如果是开发一款浏览器应用,为响应ACTION_VIEW操作,需要在activity声明中包含以下intent过滤器:
<activity
android:name=".BrowserActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" android:host="www.csdn.net" />
</intent-filter>
</activity>
intent过滤器中的action元素告诉操作系统,activity能够处理指定的任务;
DEFAULT类别告诉操作系统,activity愿意处理某项任务。DEFAULT类别必须明确地在intent过滤器中进行设置。
DEFAULT类别实际隐含添加到了几乎每一个隐式intent中。(唯一的例外是LAUNCHER类别)。
有时间再探索下这个Intent过滤器的使用^_^
如同显式intent,隐式intent也可以包含extra信息。不过,操作系统在寻找适用的activity时,它不会使用任何附加在隐式intent上的extra。
一些需要extra数据的隐式intent,我们可以使用 putExtra() 方法来添加那些数据。
默认的,系统会根据Uri数据类型来决定需要哪些合适的MIME type。如果我们没有在intent中包含一个Uri, 则通常需要使用 setType() 方法来指定intent附带的数据类型。设置MIME type 是为了指定应该接受这个intent的activity。
例如,发送一个带附件的email:
Intent emailIntent = new Intent(Intent.ACTION_SEND);
// 这个 intent 没有一个URI, 因此需要声明"text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"[email protected]"}); // 收件人
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email 主题");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email的文本信息");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// 你也可以附加多个项通过ArrayList<Uris>
注意:请尽可能的将隐式Intent定义的更加确切。例如,如果想要使用ACTION_VIEW 的intent来显示一张图片,则还应该指定 MIME type 为
image/*
.这样能够阻止其他能够 “查看” 其他数据类型的app(比如一个地图app) 被这个intent唤起。
Intent 类将为标准化的数据类型指定多个 EXTRA_*
常量。
如需声明自己的附加数据键(对于应用接收的 Intent ),请确保将应用的软件包名称作为前缀。
例如:
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
尽管Android系统会确保每一个确定的intent会被系统内置的app(如the Phone, Email, or Calendar app)之一接收,但是我们还是应该在触发一个intent之前做验证是否有App接受这个intent的步骤。
Note:如果系统没有对应的activity被唤起,则应用会崩溃!
为了验证是否有合适的activity会响应这个intent,
需要执行queryIntentActivities()
方法来获取到能够接收这个intent的所有activity的列表。
若返回的activity列表非空,那么我们才可以安全的使用这个intent。
下面是一个演示了如何创建一个intent来查看通讯录联系人的完整例子,首先验证有app可以处理这个intent,然后启动它
// 新建的隐式intent将由操作以及数据获取位置组成。
// 操作为Intent.ACTION_PICK
// 数据位置为ContactsContract.Contacts.CONTENT_URI,联系人通讯录
Intent i = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
// 检查设备中可以响应的activity
PackageManager pm = getActivity().getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(i, 0);
boolean isIntentSafe = activities.size() > 0;
if (isIntentSafe) {
// 需要从打开的activity中获得返回数据
startActivityForResult(i, CONTACT_REQUEST_CODE);
}
Note:我们必须在第一次使用之前做这个检查,若是不可行,则应该关闭这个功能。
当创建好了intent并且设置好了extra数据后,通过执行startActivity() 将intent发送到系统。若系统确定了多个activity可以处理这个intent,它会显示出一个对话框,让用户选择启动哪个app。如果系统发现只有一个app可以处理这个intent,则系统将直接启动该app。
startActivity(intent);
当以startActivity()
的形式传递一个intent,并且有多个app可以处理时,用户可以在弹出对话框的时候选择默认启动的app(通过勾选对话框下面的选择框,如上图所示)。该功能对于用户有特殊偏好的时候非常有用(例如用户总是喜欢启动某个app来查看网页,总是喜欢启动某个camera来拍照)。
然而,如果用户希望每次都弹出选择界面,而且每次都不确定会选择哪个app启动,例如分享功能,用户选择分享到哪个app都是不确定的,这个时候,需要强制弹出选择的对话框。(这种情况下用户不能选择默认启动的app)。
为了显示选择对话框, 需要使用createChooser()
来创建Intent。
Intent intent = new Intent(Intent.ACTION_SEND);
...
// 分享对话框的标题
String title = getResources().getText(R.string.chooser_title);
// 创建和启动选择器
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);
这样就列出了可以响应createChooser()
中Intent的app,并且指定了标题。
// 创建文本信息
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
// 验证是否有可解析该Intent的activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}
Note:该示例并没有使用 URI,但已声明 Intent 的数据类型,用于指定 Extra 携带的内容。
例如,以下是一个使用 Intent 过滤器进行的 Activity 声明,当数据类型为文本时,系统将接收 ACTION_SEND Intent :
<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>
Note:显式 Intent 始终会传递给其目标,无论组件声明的 Intent 过滤器如何均是如此。
可以创建一个包括多个 <action>
、<data>
或 <category>
实例的过滤器。创建时,仅需确定组件能够处理这些过滤器元素的任何及所有组合即可。
如需仅以操作、数据和类别类型的特定组合来处理多种 Intent,则需创建多个 Intent 过滤器。
系统通过将 Intent 与所有这三个元素进行比较,根据过滤器测试隐式 Intent。隐式 Intent 若要传递给组件,必须通过所有这三项测试。
如果 Intent 甚至无法匹配其中任何一项测试,则 Android 系统不会将其传递给组件。但是,由于一个组件可能有多个 Intent 过滤器,因此未能通过某一组件过滤器的 Intent 可能会通过另一过滤器。
Android学习之基于显式的Intent的通讯
参考资料:
http://developer.android.com/training/basics/intents/sending.html