注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接: http://developer.android.com/training/basics/intents/sending.html
Android的一个最重的特性就是一个应用可以将用户带领到另一个应用的能力,这一切基于的是一个应用期望表现的“ 行为(action) ”。例如,如果你的应用有一个你期望显示在地图上的地址,你不需要在你的应用中构建一个显示地图的Activity,你只需要通过使用 Intent 来创建一个查勘地址的需求。之后Android系统会自动启动一个可以在地图上显示地址的应用。
如同在第一节课 Building Your First App (博客链接: http://www.cnblogs.com/jdneo/p/3438954.html )所说的,你必须使用intents在你的应用的Activity之间转换。一般你通过显示intent来做这件事情,这将指明你希望启动的组件的类名。然而,当你希望通过另一个应用执行一个行为,比如“查看地图”,你就必须使用一个隐式的intent。
这节课将向你展示如何为一个特定的行为创建一个隐式intent,以及如何使用它启动一个其它应用的Activity来执行这个行为。
一). 构建一个隐式的Intent
隐式Intent不声明要启动组件的类名,而是声明一个要执行的行为。该行为指定了你希望做的事情,比如查看,编辑,发送或者获取某些东西。Intents也经常包含与该行为有关的数据,比如你希望查看的地址,或者你希望发送的邮件内容。根据你希望创建intent,数据可以是一个 Uri ,也可以其他的数据类型,当然intent也可以不需要任何数据。
如果你的数据是一个
Uri
,有一个你可以使用的
Intent()
构造函数来定义行为和数据。
下述例子是如何使用 Uri 数据指定电话号码来创建一个intent,从而初始化一个打电话行为
Uri number = Uri.parse("tel:5551234" ); Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
当你的应用通过调用 startActivity() 行使了这个intent,拨号应用会根据给定的电话号码初始化一个呼叫。
下面是一些其他intent的例子,以及它们所对应的行为和 Uri 数据对:
- 浏览地图:
// Map point based on address Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California" ); // Or map point based on latitude/longitude // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
- 浏览一个网页:
Uri webpage = Uri.parse("http://www.android.com" ); Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
其它类型的隐式Intents需要“ extra ”数据来提供不同的数据类型,比如字符串。你通过使用不同的 putExtra() 方法来添加一个或多个“ extra ”数据。
默认的,系统会基于intent所包含的
Uri
数据,来指定它所需要的恰当MIME类型。如果你在intent中不包含一个
Uri
,你应该使用
setType()
来指定与该intent所关联的数据类型。设置MIME类型会进一步特定什么类型的Activity将会接受这个intent。
下面是一些intent例子,它们通过添加额外的数据来定义希望的行为:
- 发送一个有附件的Email:
Intent emailIntent = new Intent(Intent.ACTION_SEND); // The intent does not have a URI, so declare the "text/plain" MIME type emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject" ); emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text" ); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse( "content://path/to/email/attachment" )); // You can also attach multiple items by passing an ArrayList of Uris
- 创建一个日历事件:
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30 ); Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30 ); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); calendarIntent.putExtra(Events.TITLE, "Ninja class" ); calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
Note:
这个日历事件的Intent仅在API Level 14或更高的平台上被支持。
Note:
将你的 Intent 定义的越明确越好!例如,如果你希望使用 ACTION_VIEW 的intent来展示一个图片,你应该特定MIME类型为“ image/* ”。这将防止可以查看其他数据类型的应用(比如一个地图阅览器)被这个intent激活。
二). 确认有一个应用能接受此Intent
虽然Android平台保证某个Intent将会由一个内置的应用所处理(比如:电话,电子邮件或者日历等应用),但是你在激活一个intent前包含一个确认的步骤。
Caution:
如果你激活了一个在设备中没有任何一个应用能够处理该事务的intent,那么你的应用将会崩溃。
为了确认有一个应用能够正确响应这个intent,调用
queryIntentActivities()
来得到一个能够处理你的
Intent
的activity清单。如果返回的
List
不为空,你可以安全地使用这个intent。例如:
PackageManager packageManager = getPackageManager(); List <ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0 ); boolean isIntentSafe = activities.size() > 0;
如果 isIntentSafe为真,那就说明至少有一个应用能够正确响应这个intent。如果为假,那就说明没有任何应用能够处理这个intent。
Note:
你应该在你的应用第一次启动时执行这个检查,这样你就可以禁用使用该intent的功能特性,防止用户尝试去使用它。如果你知道某个特定的应用能够处理这个intent,你也可以给用户提供链接来让用户下载这个应用(可也查阅: link to your product on Google Play )
三). 通过Intent启动一个Activity
一旦你创建了你的 Intent 并且设置了额外的信息,你可以调用 startActivity() 将它发送给系统。如果系统发现有不止一个acitivity可以处理这个intent,它会向用户显示一个对话框,让用户选择要启动哪一个应用,如图1所示。如果只有一个应用能够处理这个intent,那么系统会立即直接启动它。
startActivity(intent);
图1. 当有多个应用能够处理该intent时,系统所显示的选择对话框
下面是一个完整的例子,它显示了如何创建一个intent来浏览一个地图,然后确认是否存在应用能够处理它,然后启动它:
// Build the intent Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California" ); Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); // Verify it resolves PackageManager packageManager = getPackageManager(); List <ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0 ); boolean isIntentSafe = activities.size() > 0 ; // Start an activity if it's safe if (isIntentSafe) { startActivity(mapIntent); }
四). 显示一个应用选择器(App Chooser)
注意到当你将你的 Intent 传递给 startActivity() 来启动一个Activity时,如果有多个应用可以正确响应这个intent,用户可以选择默认使用哪个程序(在对话框底部勾选复选框,见图1)。当用户每次都希望使用相同的应用来处理该事务时(比如打开一个网页时,用户可能会喜欢只用一个浏览器,或者拍摄一个照片,用户可能只喜欢用一款相机应用),此时这么做是不错的。
然而,如果这个intent行为可以被多个应用处理,同时,用户每次可能期望使用不同的应用——比如“ 分享 ”这一行为,用户可能有多个应用能够分享某一个项目。此时你应该显式地展现一个选择应用的对话框,如图2所示。这个对话框强制用户在每次执行该操作时,选择一个自己期望的应用来处理该事务(用户不能选择一个默认的应用来处理)。
图2. 一个应用选择器对话框
为了显示一个选择器,使用 createChooser() 来创建一个intent,并将它传递给 startActivity() ,例如:
Intent intent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create and start the chooser Intent chooser = Intent.createChooser(intent, title); startActivity(chooser);
这样将会显示一个对话框,里面显示了能够处理传递给 createChooser() 的intent的应用清单,对话框的标题是代码中指定的文本。