与其他应用 交互

构建隐含 Intent

如果您的数据是 Uri,您可以使用一个简单的 [Intent()](https://developer.android.google.cn/reference/android/content/Intent.html#Intent(java.lang.String, android.net.Uri))构造函数来定义操作和数据。
例如
此处显示如何使用指定电话号码的 Uri 数据创建发起电话呼叫的 Intent:、

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

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

查看网页:

Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

其他类型的隐含 Intent 需要提供不同数据类型(比如,字符串)的“额外”数据。 您可以使用各种 [putExtra()](https://developer.android.google.cn/reference/android/content/Intent.html#putExtra(java.lang.String, java.lang.String))方法添加一条或多条 extra 数据。
默认情况下,系统基于所包含的 Uri数据确定 Intent 需要的相应 MIME 类型。如果您未在 Intent 中包含 Uri,您通常应使用 setType()
指定与 Intent 关联的数据的类型。**设置 MIME 类型可进一步指定哪些类型的 Activity 应接收 Intent。
**
此处有更多添加额外数据以指定所需操作的 Intent:

  • 发送带附件的电子邮件:
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。

:尽可能具体地定义您的 Intent非常重要。例如,如果您想要使用 ACTION_VIEW Intent 显示图像,
您应指定 MIME 类型 image/*。
这可防止可“查看”数据的其他类型的应用(比如地图应用)被 Intent 触发

验证是否存在接收 Intent 的应用

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

要确认是否存在可响应 Intent 的可用 Activity,请调用 [queryIntentActivities()](https://developer.android.google.cn/reference/android/content/pm/PackageManager.html#queryIntentActivities(android.content.Intent, int))来获取能够处理您的 Intent的 Activity 列表。如果返回的 List不为空,您可以安全地使用该 Intent。
例如:

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

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

启动具有 Intent 的 Activity

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

一旦您已创建您的 Intent并设置 extra 信息,调用 startActivity() 将其发送给系统。
如果系统识别可处理 Intent 的多个 Activity,它会为用户显示对话框供其选择要使用的应用,如图 1 所示。如果只有一个 Activity 处理 Intent,系统会立即将其启动。
startActivity(intent);
此处显示完整的示例:如何创建查看地图的 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);
}

显示应用选择器

注意,当您通过将您的 Intent传递至 startActivity()
而启动 Activity 时,有多个应用响应 Intent,用户可以选择默认使用哪个应用(通过选中对话框底部的复选框;见图 1)。

图 2. 选择器对话框。
当执行用户通常希望每次使用相同应用进行的操作时,比如当打开网页(用户可能只使用一个网络浏览器)或拍照(用户可能习惯使用一个相机)时,这非常有用。
但是,如果要执行的操作可由多个应用处理并且用户可能 习惯于每次选择不同的应用 — 比如“共享”操作, 用户有多个应用分享项目 — 您应明确显示选择器对话框, 如图 2 所示。选择器对话框 强制用户选择用于每次操作的 应用(用户不能对此操作选择默认的应用)。要显示选择器,请使用 [createChooser()](https://developer.android.google.cn/reference/android/content/Intent.html#createChooser(android.content.Intent, java.lang.CharSequence))创建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()](https://developer.android.google.cn/reference/android/content/Intent.html#createChooser(android.content.Intent, java.lang.CharSequence)) 方法的 Intent 的应用列表,并且将提供的文本用作对话框标题。

获取 Activity 的结果

启动另一个 Activity 并 接收返回的结果
请调用 [startActivityForResult()](https://developer.android.google.cn/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))(而不是 startActivity())。

:当您调用 [startActivityForResult()](https://developer.android.google.cn/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)) 时,您可以使用明确或隐含 Intent。当启动您自己的 Activity 以接收结果时,您应使用明确 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()](https://developer.android.google.cn/reference/android/app/Activity.html#onActivityResult(int, int, android.content.Intent)) 的方法。此方法包括三个参数:

本例说明您可以如何处理“选择联系人” 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)
        }
    }
}
更多 向您展示如何查询结果数据,从所选联系人获取电话号码:
@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](https://developer.android.google.cn/reference/android/content/CursorLoader.html) 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 版本开始,“联系人”应用授予您的应用在联系人提供程序向您返回结果时从联系人提供程序临时读取信息的权限。 该临时权限仅适用于所请求的特定联系人,因此您只能查询 Intent 的 Uri指定的联系人,除非您声明 READ_CONTACTS权限。

允许其他应用启动您的 Activity

要允许其他应用启动您的 Activity,您需要在清单文件中为对应的 <activity>
元素添加一个 <intent-filter>
元素。
当您的应用安装在设备上时,系统会识别您的 Intent 过滤器并添加信息至所有已安装应用支持的 Intent 内部目录。当应用通过隐含 Intent 调用 startActivity()或 [startActivityForResult()](https://developer.android.google.cn/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))时,系统会找到可以响应该 Intent 的 Activity。

添加 Intent 过滤器

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

操作

对要执行的操作命名的字符串。通常是平台定义的值之一,比如 ACTION_SENDACTION_VIEW。使用 <action>
元素在您的 Intent 过滤器中指定此值。您在此元素中指定的值必须是操作的完整字符串名称,而不是 API 常量(请参阅以下示例)。

数据

与 Intent 关联的数据描述。用 <data>
元素在您的 Intent 过滤器中指定此内容。使用此元素中的一个或多个属性,您可以只指定 MIME 类型、URI 前缀、URI 架构或这些的组合以及其他指示所接受数据类型的项。

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

类别

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

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

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

比如,假定您的 Activity 同时处理 ACTION_SENDACTION_SENDTO Intent 的文本和图像。在这种情况下,您必须为两个操作定义两种不同的 Intent 过滤器,因为 ACTION_SENDTO Intent 必须使用数据 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>

注:为了接收隐含 Intent,您必须在 Intent 过滤器中包含 CATEGORY_DEFAULT类别。方法 startActivity()和[startActivityForResult()](https://developer.android.google.cn/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))将按照已声明 CATEGORY_DEFAULT类别的方式处理所有 Intent。如果您不在 Intent 过滤器中声明它,则没有隐含 Intent 分解为您的 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();
    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()](https://developer.android.google.cn/reference/android/app/Activity.html#setResult(int, android.content.Intent))指定结果代码和结果 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_OKRESULT_CANCELED。您之后可以根据需要为 Intent提供额外的数据。

:默认情况下,结果设置为 RESULT_CANCELED。因此,如果用户在完成操作动作或设置结果之前按了返回按钮,原始 Activity 会收到“已取消”的结果。

如果您只需返回指示若干结果选项之一的整数,您可以将结果代码设置为大于 0 的任何值。如果您使用结果代码传递整数,且无需包括 Intent,则可调用 setResult()且仅传递结果代码。例如:

setResult(RESULT_COLOR_RED);
finish();

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

:无需检查您的 Activity 是使用 startActivity() 还是 [startActivityForResult()](https://developer.android.google.cn/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))启动的。如果启动您 Activity 的 Intent 可能需要结果,只需调用 [setResult()](https://developer.android.google.cn/reference/android/app/Activity.html#setResult(int, android.content.Intent))。如果原始 Activity 已调用 [startActivityForResult()](https://developer.android.google.cn/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)),则系统将向其传递您提供给 [setResult()](https://developer.android.google.cn/reference/android/app/Activity.html#setResult(int, android.content.Intent))的结果;否则,会忽略结果。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容