- 一个android app可以有许多activities。每个activity给用户提供一个用户接口来操作具体的任务(比如查看地图或者拍照)。为了将用户从一个activity带到另一个activity,你的app必须使用intent来定义你的app的“意向”。当你给一个函数比如startActivity()传递一个Intent,系统就会使用Intent来确定并且启动合适的app组件。使用intents也允许你的app启动一个包含在其他app中的activity。
- 一个Intent可以是explicit(具体的)来启动一个确定的组件(一个具体的activiyt实例)或者是implicit(不具体的)来启动任何可以满足该“意向”的组件比如(获取图片)
- 本节课程使用intent来执行一些基本的和其他app进行交互的动作,比如启动另一个app,从另一个app中接收结果。让你的app能够响应别的app的“intent”
将用户带到其他app中去
- 比如说你的app有一个需要在地图上显示的地址,你不需要在你的app中新建一个activity来展示在map上,相应的你可以使用Intent来请求查看地图上该地址的位置。android系统然后就会打开一个可以在地图上显示位置的app。
- 如果你使用过intent在各个activities之间转换。一般你会用一个具体的intent,包括定义具体的你想打开的组件的类名称。但是,类似查看地图这种需要一个独立app来执行相应动作的工作,需要使用implicit intent。本节课会展示如何为一个特定的动作创建一个implicit action,并且如何使用它来打开另一个app中的activity来执行这个动作。
创建一个implicit intent
- implicit intents不会声明需要打开的组件的类名。但是相应的会声明要进行的操作。这个声明会指定你想要做的事,比如view,edit,send,或者是得到一些东西。intents通常也会包含与该操作相关联的数据,比如你想查看的地址,或者你想发送的邮件消息。根据你想要创建的intent,数据可能是uri,或者其他类型数据中的一种,更或者这个intent一点也不需要数据。
- 如果你的数据是uri,有一个简单的Intent()构造函数用来定义action和data。
比如,以下是如何使用uri data创建一个intent去初始化phone call:
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
当你的app通过startActivity()来调用这个intent,Phone app会根据所给的phone number来拨打电话。
以下是其他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);
- 其他类型的implicit intents需要额外数据。比如说string。你可以使用各种putExtra()方法来添加一个或者更多的额外数据。
- 默认情况下,系统会根据intent包含的uri数据来确定合适的MIME类型。如果你没有在intent中包含一个uri,你就应该使用setType()来确定和intent关联的数据类型。设置MIME type会进一步来确定哪种activities应该接受这种intent。
以下是添加了extra data的intents来确定希望的action:
发送带附件的邮件:
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
创建日历事件:
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");
注意:这个calendar event 的intent只支持API level 14和以上。
将你的intent定义的尽可能具体是非常重要的。比如:如果你想使用ACTION_VIEW intent来展示一个图像,你应该将MIME type具体为image/* 。这样可以防止其他可以view其他类型数据(比如map app)的app被intent引发。
检测是否有app来接收intent
尽管android 平台保证具体的intents会被至少一个自带的应用(比如phone,email,calendar app)解决。但是你应该总是在调用intent前进行检验。
注意:如果你调用了一个intent,但是你的设备上没有可以处理这个intent的app,你的应用就会死掉。
* 为了检验是否有一个activity可以响应intent,调用queryIntentActivities()来获取可以响应你的intent的activities的列表。如果返回的List不是空的,你就可以安全的使用intent,比如:
PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;
如果isIntentSafe是true,那么至少有一个app可以响应intent。如果是false,没有一个app可以响应这个intent。
注意:当你的activity第一次打开,你应该执行这个检查以防止用户用它之前你禁止使用这个intent的特色。如果你知道具体的一个软件可以识别你的intent,你也可以给用户提供一个链接去下载该应用。
使用intent来启动activity
一旦你创建自己的Intent并且设置了额外的信息。调用startActivity()来将它传递给系统。如果系统识别出几个可以处理这个intent的activity,它会给用户展示一个对话框来选择具体的app。如果只有一个activity可以响应这个intent,系统会立即启动该activity
startActivity(intent);
以下是一个复杂点得例子来展示如何创建一个查看map的intent,验证如果有一个app可以处理该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选择框
注意到当你通过传递Intent给startActivity()函数来启动一个activity并且超过一个app可以响应这个intent,默认用户可以选择一个app(通过选择底部的checkbox)。当然让用户选择是否每次都是用同一个应用打开类似的操作是非常有好的。
但是,如果每次执行相同的动作都需要不同的app-比如“分享”这个动作。可能用户每次都会有不同的选择。那你的app就应该每次都给用户提供选择。
为了展示选择框,使用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 intent to show chooser
Intent chooser = Intent.createChooser(intent, title);
// Verify the intent will resolve to at least one activity
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
这段代码展示一个可以响应该操作的对话框列表并且使用提供的text作为对话框的标题。