您的位置:首页 > 移动开发

与其他APP进行交互

2016-06-14 20:41 417 查看
来自:https://developer.android.com/training/basics/intents/index.html

前言:我们都知道在APP中共享数据是非常重要的。比如我们经常会在微信中打开腾讯新闻APP进行新闻的查看,然后还可以选择是留在腾讯新闻APP界面还是返回微信原界面,这就涉及到APP之间进行数据传输问题。还有一个强需求场景就是:在图库中选择图片进行发送,这时候就会弹出各种供选择的APP,我一般选择发送到电脑,然后就会启动QQ中的发送到电脑的Activity界面,实现图片的发送。所以,掌握怎样在APP之间传递数据是非常重要的。

Android 应用一般具有若干个Activity。每个Activity显示一个用户界面,用户可通过该界面执行特定任务(比如,查看地图或拍照)。要将用户从一个Activity转至另一Activity,您的应用必须使用
Intent
定义您的应用做某事的“意向”。当您使用诸如
startActivity()
的方法将
Intent
传递至系统时,系统会使用
Intent
识别和启动相应的应用组件。使用意向甚至可以让您的应用开始另一个应用中包含的Activity。

Intent
可以为显式以便启动特定组件(特定的
Activity
实例)或隐式以便启动处理意向操作(比如“拍摄照片”)的任何组件。

向另一个应用发送用户

Android 最重要的功能之一是应用能够基于它要执行的“操作”向另一个应用发送用户。 例如,如果您的应用有您要在地图上显示的公司地址,您无需在显示地图的应用中构建Activity。而是可以创建使用
Intent
查看地址的请求。Android
系统之后启动可以在地图上显示该地址的应用。

您必须使用意向在自己应用中的Activity之间进行导航。您通常使用明确意向执行此操作,该意向定义您希望启动的组件的确切类名称。 但是,当您希望另一应用执行操作时,比如“查看地图”,您必须使用隐含意向。

构建隐含意向

隐含意向不声明要启动的组件的类名称,而是声明要执行的操作。 该操作指定您要执行的操作,比如查看、编辑、发送或 获取 某项。
意向通常还包含与操作关联的数据,比如您要查看的地址或您要发送的电子邮件消息。根据要创建的意向,数据可能是
Uri
、多种其他数据类型之一,或意向可能根本就不需要数据。

如果您的数据是
Uri
,有一个简单的
Intent()
构造函数,您可用来定义操作和数据。

例如,此处显示如何使用指定电话号码的
Uri
数据创建发起电话呼叫的意向:
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);


当您的应用通过调用
startActivity()
调用此意向时,“电话”应用会发起向指定电话号码的呼叫。

这里有一些其他意向及其操作和
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);


其他类型的隐含意向需要提供不同数据类型(比如,字符串)的“额外”数据。 您可以使用各种
putExtra()
方法添加一条或多条额外数据。

默认情况下,系统基于所包含的
Uri
数据确定意向需要的相应 MIME 类型。如果您未在意向中包含
Uri
,您通常应使用
setType()
指定与意向关联的数据的类型。设置
MIME 类型可进一步指定哪些类型的Activity应接收意向。

此处有更多添加额外数据以指定所需操作的意向:

发送带附件的电子邮件:
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");


注意:只有 API 级别 14 或更高级别支持此日历事件意向。

注意:尽可能具体地定义您的
Intent
非常重要。例如,如果您想要使用
ACTION_VIEW
意向显示图像,您应指定
image/*

MIME 类型。 这可防止可“查看”数据的其他类型的应用(比如地图应用)被意向触发。

确认是否存在接收意向的应用

尽管 Android 平台保证某些意向可以分解为内置应用之一(比如,“电话”、“电子邮件”或“日历”应用),您应在调用意向之前始终包含确认步骤。

注意:如果您调用了意向,但设备上没有可用于处理意向的应用,您的应用将崩溃。

要确认是否存在可响应意向的可用Activity,请调用
queryIntentActivities()
来获取能够处理您的
Intent
的Activity列表。如果返回的
List
不为空,您可以安全地使用该意向。例如:

PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;


如果
isIntentSafe
true
,则至少有一个应用将响应该意向。 如果它是
false
,则没有任何应用处理该意向。

开始具有意向的Activity



图 1.当多个应用可处理意向时显示的选择对话框示例。

一旦您已创建您的
Intent
并设置附加信息,调用
startActivity()
将其发送给系统
。如果系统识别可处理意向的多个Activity,它会为用户显示对话框供其选择要使用的应用,如图 1 所示。如果只有一个Activity处理意向,系统会立即开始这个Activity。

startActivity(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);
}

显示应用选择器

注意,当您通过将您的
Intent
传递至
startActivity()
而开始Activity时,有多个应用响应意向,用户可以选择默认使用哪个应用(通过选中对话框底部的复选框;见图
1)。当执行用户通常希望每次使用相同应用进行的操作时,比如当打开网页(用户可能只使用一个网页浏览器)或拍照(用户可能习惯使用一个照相机)时,这非常有用。

但是,如果要执行的操作可由多个应用处理并且用户可能习惯于每次选择不同的应用,—比如“共享”操作,用户有多个应用分享项目—,您应明确显示选择器对话框,如图 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 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);
}


这将显示一个对话框,其中有响应传递给
createChooser()
方法的意向的应用列表,并且将提供的文本用作对话框标题。

获取Activity的结果

开始并不一定是单向的另一个Activity。您还可以开始另一个Activity并 接收返回的结果。要接收结果,请调用
startActivityForResult()
(而不是
startActivity()
)。

例如,您的应用可启动照相机应用并接收拍摄的照片作为结果。或者,您可以启动“联系人”应用以便用户选择联系人,并且您将接收联系人详细信息作为结果。

当然,响应的Activity必须设计为返回结果。当它这样做时,它会作为另一
Intent
对象发送结果。您的Activity在
onActivityResult()
回调中接收它。

注意:当您调用
startActivityForResult()
时,您可以使用明确或隐含意向。当开始您自己的Activity以接收结果时,您应使用明确意向确保您可收到预期结果。

开始Activity

开始针对结果的Activity时,您所使用的
Intent
对象并没有什么特别之处,但您需要向
startActivityForResult()
方法传递额外的整数参数。

该整数参数是识别您的请求的“请求代码”。当您收到结果
Intent
时,回调提供相同的请求代码,以便您的应用可以正确识别结果并确定如何处理它。

例如,此处显示如何开始允许用户选择联系人的Activity:

static final int PICK_CONTACT_REQUEST = 1;  // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}

接收结果

当用户完成后续Activity并且返回时,系统会调用您的Activity
onActivityResult()
的方法。此方法包括三个参数:

您向
startActivityForResult()
传递的请求代码。
第二个Activity指定的结果代码。如果操作成功,这是
RESULT_OK
;如果用户退出或操作出于某种原因失败,则是
RESULT_CANCELED

传送结果数据的
Intent


本例说明您可以如何处理“选择联系人”意向的结果。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.

// Do something with the contact here (bigger example below)
}
}
}

在本例中,Android的“联系人”应用返回的结果
Intent
提供识别用户所选联系人的内容
Uri


为了成功处理结果,您必须了解结果的
Intent
的格式。当返回结果的Activity是您自己的Activity之一时,这便非常容易。 Andriod平台附带的应用提供它们自己的API,您可用这些API获取特定结果数据。
例如,“联系人” 应用(在一些较旧的版本中是 Contacts 应用)始终返回带内容 URI(识别所选联系人)的结果,并且“照相机” 应用在
"data"
额外项中返回
Bitmap
(请参阅有关拍摄照片的课程)。


接收联系人数据

显示如何从“联系人”应用获取结果的代码不会详细说明如何实际从结果读取数据,但它需要对内容提供商进行更深入的探讨。但是,如果您很好奇,此处提供了更多的代码向您展示如何查询结果数据,从所选联系人获取电话号码:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request it is that we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// Get the URI that points to the selected contact
Uri contactUri = data.getData();
// We only need the NUMBER column, because there will be only one row in the result
String[] projection = {Phone.NUMBER};

// Perform the query on the contact to get the NUMBER column
// We don't need a selection or sort order (there's only one result for the given URI)
// CAUTION: The query() method should be called from a separate thread to avoid blocking
// your app's UI thread. (For simplicity of the sample, this code doesn't do that.)
// Consider using CursorLoader to perform the query.
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst();

// Retrieve the phone number from the NUMBER column
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column);

// Do something with the phone number...
}
}
}

注意:在 Android 2.3(API 级别 9)之前,在
Contacts
Provider
上执行查询(如以上所示)需要您的应用声明
READ_CONTACTS
权限(请参阅安全与权限)。
但是,自 Android 2.3 版本开始,“联系人”应用授予您的应用在联系人提供商向您返回结果时从联系人提供商临时读取信息的权限。该临时权限仅适用于所请求的特定联系人,因此您只能查询意向的
Uri
指定的联系人,除非您声明
READ_CONTACTS
权限。

允许其他应用开始您的Activity

前两课重点讲述一方面:从您的应用开始另一个应用的Activity。但如果您的应用可以执行对另一个应用可能有用的操作,您的应用应准备好响应来自其他应用的操作请求。例如,如果您构建一款可与用户的好友分享消息或照片的社交应用,您最关注的是支持
ACTION_SEND
意向以便用户可以从另一应用发起“共享”操作并且启动您的应用执行该操作。

要允许其他应用开始您的Activity,您需要
<intent-filter>
在相应元素的宣示说明文件中添加一个
<activity>
元素。

当您的应用安装在设备上时,系统会识别您的意向过滤器并添加信息至所有已安装应用支持的意向内部目录。当应用通过隐含意向调用
startActivity()
startActivityForResult()
时,系统会找到可以响应该意向的Activity。

添加意向过滤器

为了正确定义您的Activity可处理的意向,您添加的每个意向过滤器在操作类型和Activity接受的数据方面应尽可能具体。

如果Activity具有满足以下
Intent
对象条件的意向过滤器,系统可能向Activity发送给定的
Intent


操作对要执行的操作命名的字符串。通常是平台定义的值之一,比如
ACTION_SEND
或A
CTION_VIEW

使用
<action>
元素在您的意向过滤器中指定此值。您在此元素中指定的值必须是操作的完整字符串名称,而不是API常数(请参阅以下示例)。
数据与意向关联的数据描述。
<data>
元素在您的意向过滤器中指定此内容。使用此元素中的一个或多个属性,您可以只指定MIME类型、URI前缀、URI架构或这些的组合以及其他指示所接受数据类型的项。

注意:如果您无需声明关于数据的具体信息
Uri
(比如,您的Activity处理其他类型的“额外”数据而不是 URI 的时间),您应只指定
android:mimeType
属性声明您的Activity处理的数据类型,比如
text/plain
image/jpeg

类别提供另外一种表征处理意向的Activity的方法,通常与用户手势或Activity开始的位置有关。 系统支持多种不同的类别,但大多数都很少使用。 但是,所有隐含意向默认使用
CATEGORY_DEFAULT
进行定义。
<category>
元素在您的意向过滤器中指定此内容。

在您的意向过滤器中,您可以通过声明嵌套在
<intent-filter>
元素中的具有相应 XML 元素的各项,来声明您的Activity接受的条件。

例如,此处有一个在数据类型为文本或图像时处理
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"/>
<data android:mimeType="image/*"/>
</intent-filter>
</activity>


每个入站意向仅指定一项操作和一个数据类型,但可以在每个
<intent-filter>
中声明
<action>
<category>
<data>
元素的多个实例。

如果任何两对操作和数据的行为相斥,您应创建单独的意向过滤器指定与哪种数据类型配对时哪些操作可接受。

比如,假定您的Activity同时处理
ACTION_SEND
ACTION_SENDTO
意向的文本和图像。在这种情况下,您必须为两个操作定义两种不同的意向过滤器,因为
ACTION_SENDTO
意向必须使用数据
Uri
指定使用
send
sendto
URI架构的收件人地址。
例如:

<activity android:name="ShareActivity">
<!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
<intent-filter>
<action android:name="android.intent.action.SENDTO"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="sms" />
<data android:scheme="smsto" />
</intent-filter>
<!-- filter for sending text or images; accepts SEND action and text or image data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>


注意:为了接收隐含意向,您必须在意向过滤器中包含
CATEGORY_DEFAULT
类别。方法
startActivity()
startActivityForResult()
就像声明
CATEGORY_DEFAULT
类别那样处理所有意向。如果您不在意向过滤器中声明它,则没有隐含意向分解为您的Activity。

如需了解有关发送和接收
ACTION_SEND
执行社交共享行为的意向的详细信息,请参阅有关从其他应用接收简单数据的课程。

处理您的Activity中的意向

为了决定在您的Activity执行哪种操作,您可读取用于开始Activity的
Intent


当您的Activity开始时,调用
getIntent()
检索开始Activity的
Intent
。您可以在Activity生命周期的任何时间执行此操作,但您通常应在早期回调时(比如,
onCreate()
onStart()
)执行。

例如:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// Get the intent that started this activity
Intent intent = getIntent(); //在启动Activity的时候获得Intent,进而获得数据然后显示出来
Uri data = intent.getData();

// Figure out what to do based on the intent type
if (intent.getType().indexOf("image/") != -1) {
// Handle intents with image data ...
} else if (intent.getType().equals("text/plain")) {
// Handle intents with text ...
}
}

返回结果

如果您想要向调用您的Activity的Activity返回结果,只需调用
setResult()
指定结果代码和结果
Intent
。当您的操作完成且用户应返回原始Activity时,调用
finish()
关闭(和销毁)您的Activity。
例如:
// Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();


您必须始终为结果指定结果代码。通常,它为
RESULT_OK
RESULT_CANCELED
。您之后可以根据需要为
Intent
提供额外的数据。

注意:结果默认设置为
RESULT_CANCELED
。因此,如果用户在完成操作动作或设置结果之前按了返回按钮,原始Activity会收到“已取消”的结果。
如果您只需返回指示若干结果选项之一的整数,您可以将结果代码设置为大于 0 的任何值。 如果您使用结果代码传递整数,并且您无需包含
Intent
,您可以调用
setResult()
并且仅传递结果代码。
例如:
setResult(RESULT_COLOR_RED);
finish();


在这种情况下,只有几个可能的结果,因此结果代码是一个本地定义的整数(大于 0)。 当您向自己应用中的Activity返回结果时,这将非常有效,因为接收结果的Activity可引用公共常数来确定结果代码的值。

注意:无需检查您的Activity是使用
startActivity()
还是
startActivityForResult()
开始的。如果开始您的Activity的意向可能需要结果,只需调用
setResult()
。如果原始Activity已调用
startActivityForResult()
,则系统将向其传递您提供给
setResult()
的结果;否则,会忽略结果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: