【Android training】与其他应用交互 Intent

来源:互联网 发布:ubuntu安装golang1.7 编辑:程序博客网 时间:2024/05/20 08:01

和其他apps 交互(原文链接) 部分翻译,添加一些其他内容。

 

Android应用程式通常有几项Activities。 每个Activity显示一个允许用户执行特定任务的用户界面(如查看地图或拍摄照片)。要让用户从一个Activity到另一个Activity,您的应用程序必须使用Intent来定义应用程序的“意图”来执行某些操作。当使用诸如startActivity()之类的方法将Intent传递给系统时,系统将使用Intent来识别并启动适当的应用程序组件。使用意图甚至允许您的应用程序启动包含在单独应用程序中的Activity。

 

为了启动可以处理预期操作的任何组件(例如“捕获照片”),Intent可以是显式的,以启动特定组件(特定Activity实例)或隐式。

 

向另一个应用发送用户

Android的最重要功能之一就是应用程式能够根据需要执行的“动作”将用户发送给其他应用程式。例如,如果您的应用程式中有要显示在地图上的商家地址,则不必在应用程式中建立一个显示地图的活动。相反,您可以创建一个使用Intent查看地址的请求。然后Android系统启动一个能够在地图上显示地址的应用程序。

 

如前所述,您必须使用意图在您自己的应用程序中的活动之间进行导航。 您通常以明确的意图执行此操作,该意图定义了要启动的组件的确切类名。但是,如果要单独执行某个操作,例如“查看地图”,则必须使用隐含意图。

 

创建一个隐式intent

隐式意图不声明要启动的组件的类名,而是声明要执行的操作。 该动作指定您要执行的操作,例如查看,编辑,发送或获取某些内容。意图通常还包括与操作相关联的数据,例如要查看的地址或要发送的电子邮件。根据您要创建的意图,数据可能是Uri,其他几种数据类型之一,或者意图可能根本不需要数据。

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

 

例如,以下是如何创建使用Uri数据发起电话的意图来指定电话号码:

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

当您的应用程序通过调用startActivity()来调用此意图时,Phone应用程序会启动对给定电话号码的呼叫。


这里有一些其他意图和他们的行动和Uri数据对:

View amap:

// Map point based on addressUri 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 levelIntent mapIntent = new Intent(Intent.ACTION_VIEW, location);

View aweb page:

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

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

 

默认情况下,系统根据包含的Uri数据确定意图所需的适当MIME(MultipurposeInternet Mail Extensions)多用途互联网邮件扩展类型。

(参考文章:http://blog.csdn.net/ouyang_peng/article/details/47102537)

 如果您不想在意图中包含Uri,则通常应该使用setType()来指定与intent相关联的数据类型。设置MIME类型进一步指定哪些类型的活动应该接收意图。

 

这里有一些更多的意图,添加额外的数据来指定所需的操作:

 

发送邮件和附件:

Intent emailIntent = new Intent(Intent.ACTION_SEND);// The intent does not have a URI, so declare the "text/plain" MIME typeemailIntent.setType(HTTP.PLAIN_TEXT_TYPE);emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipientsemailIntent.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");

验证有一个应用程序来接收意图

虽然Android平台保证某些意图将解析到其中一个内置应用程序(如电话,电子邮件或日历应用程序),但在调用意图之前,应始终包括一个验证步骤。


注意:如果您调用意图,并且设备上没有可以处理该意图的应用程序,您的应用程序将崩溃。

要验证有可用的活动可以响应意图,请调用queryIntentActivities()以获取能够处理您的Intent的活动列表。 如果返回的列表不为空,则可以安全地使用该意图。 例如:

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

如果isIntentSafe是真的,那么至少有一个应用程序将响应意图。 如果它是假的,那么没有任何应用程序来处理意图。

 

注意:当您的活动首次启动时,您应该执行此检查,以防在用户尝试使用该功能之前禁用使用意图的功能。如果您知道可以处理意图的特定应用程序,还可以提供用户下载应用程序的链接

 

使用intent启动Activity

创建Intent并设置其他信息后,调用startActivity()将其发送到系统。 如果系统识别出可以处理意图的多个活动,它将显示一个对话框,供用户选择要使用的应用程序。如果只有一个活动处理意图,系统将立即启动它。

startActivity(intent);

以下是一个完整的示例,显示如何创建查看地图的意图,验证是否存在应用程序来处理意图,然后启动它:

// Build the intentUri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);// Verify it resolvesPackageManager packageManager = getPackageManager();List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);boolean isIntentSafe = activities.size() > 0;// Start an activity if it's safeif (isIntentSafe) {    startActivity(mapIntent);}

显示应用选择器

请注意,当您通过将Intent传递给startActivity()并且有多个应用程序响应意图启动活动时,用户可以默认选择要使用的应用程序(通过选择对话框底部的复选框)。当用户希望每次使用相同应用程序的操作(例如打开网页(用户可能只使用一个网络浏览器))或拍摄照片(用户可能喜欢一个相机)时,这是很好的。

 

然而,如果要执行的操作可以由多个应用程序处理,并且用户可能更喜欢每次使用不同的应用程序,例如“共享”操作,哪些用户可能会有多个应用程序通过它们共享一个项目 - 您应该明确显示选择器对话框。选择器对话框强制用户每次选择要用于该操作的应用程序(用户无法为该操作选择默认应用程序)。

 

要显示选择器,使用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);//显示应用选择界面 Intent chooser = Intent.createChooser(intent, title);// Verify the intent will resolve to at least one activityif (intent.resolveActivity(getPackageManager()) != null) {    startActivity(chooser);}

这将显示一个对话框,其中包含响应传递给createChooser()方法的意图的应用程序列表,并使用提供的文本作为对话标题。

 

从Activity 获得返回结果

启动另一个活动不一定是单向的。 您也可以启动另一个活动并获取返回结果。 要接收结果,请调用startActivityForResult()

例如,您的应用程序可以启动相机应用程序,并因此获取捕获的照片。 或者,您可以启动“人物”应用,以便用户选择联系人,因此您将收到联系人详细信息。

 

当然,响应的活动必须定义返回结果。它将结果作为另一个Intent对象发送。您的活动在onActivityResult()回调中接收。

注意:当您调用startActivityForResult()时,可以使用显式或隐式意图。 当您启动一个自己的Activity来接收结果时,您应该使用明确的意图来确保您收到预期的结果

 

启动一个Activity

在为结果启动活动时使用的Intent对象没有什么特别的,但是您需要向startActivityForResult()方法传递一个额外的整数参数。

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

 

例如,以下是启动允许用户选择联系人的活动的方法:

static final int PICK_CONTACT_REQUEST = 1;  // The request codeprivate 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);}

接收结果

当用户完成后续活动并返回时,系统将调用您的活动的onActivityResult()方法。这个方法包括三个参数:

 

传递给startActivityForResult()的请求代码。

由第二个活动指定的结果代码。 如果操作成功,则为RESULT_OK,如果用户退出或由于某种原因操作失败,则为RESULT_CANCELED。

携带结果数据的意图。

例如,以下是如何处理“选择联系人”意图的结果:

@Overrideprotected 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的联系人应用程序返回的结果意图提供了用于标识用户选择的联系人的内容Uri。

 

为了成功处理结果,您必须了解结果Intent的格式是什么。Android平台提供的应用提供了获取特定结果数据的API。例如,联系人应用程序总是返回一个结果,其中包含标识所选联系人的内容URI,而Camera应用程序会在“数据”中返回一个Bitmap(请参阅有关捕捉照片的类)。

 

上面的代码显示了如何从People应用程序获取结果,并没有详细介绍如何从结果中实际读取数据,因为它需要关于provider的更高级的讨论。下面代码说明如何从所选联系人获取电话号码。

@Overrideprotected 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)之前,在联系人privider上执行查询(如上所示)要求您的应用程序声明READ_CONTACTS权限(请参阅安全性和权限)。然而,从Android 2.3开始,“联系人/人物”应用程序在您返回结果时,会将您的应用程序授予临时权限以从联系人provider中读取。临时权限仅适用于请求的特定联系人,因此除非您声明了READ_CONTACTS权限,否则您无法查询除意图Uri指定的联系人之外的联系人。

 

允许其他APP启动你的Activity

如果您的应用可以执行可能对另一个应用程序有用的操作,则应用程序应该准备好响应其他应用程序的操作请求。例如,如果您构建可以与用户的朋友分享消息或照片的社交应用程序,则支持ACTION_SEND意图是最有利的,以便用户可以从另一个应用程序启动“共享”操作,并启动应用程序来执行操作。

 

要允许其他应用程序启动您的活动,您需要在清单文件中为相应的<activity>元素添加一个<intent-filter>元素。

 

当您的应用程序安装在设备上时,系统会识别您的意图过滤器,并将信息添加到所有已安装应用程序支持的内部目录。当应用程序调用startActivity()或startActivityForResult()时,使用隐含的意图,系统会发现哪些活动(或活动)可以响应意图

 

添加一个Intent Filter

为了正确地定义您的活动可以处理的intent,您添加的每个意图过滤器应尽可能具体到活动可以接受的类型和数据。

 

Intent主要有以下四个重要属性,它们分别为:

(以下转自:http://blog.csdn.net/weihan1314/article/details/7973511)

Action:Action属性的值为一个字符串,它代表了系统中已经定义了一系列常用的动作。通过setAction()方法或在清单文件AndroidManifest.xml中设置。默认为:DEFAULT。

Data:Data通常是URI格式定义的操作数据。例如:tel:// 。通过setData()方法设置。

Category:Category属性用于指定当前动作(Action)被执行的环境。通过addCategory()方法或在清单文件AndroidManifest.xml中设置。默认为:CATEGORY_DEFAULT。

Extras:Extras属性主要用于传递目标组件所需要的额外的数据。通过putExtras()方法设置。

 

四个属性各自的常用值如下所示:

Action:

     ACTION_MAIN:Android Application的入口,每个Android应用必须且只能包含一个此类型的Action声明。 

    ACTION_VIEW:系统根据不同的Data类型,通过已注册的对应Application显示数据。

    ACTION_EDIT:系统根据不同的Data类型,通过已注册的对应Application编辑示数据。 

    ACTION_DIAL:打开系统默认的拨号程序,如果Data中设置了电话号码,则自动在拨号程序中输入此号码。 

    ACTION_CALL:直接呼叫Data中所带的号码。 

    ACTION_ANSWER:接听来电。 

    ACTION_SEND:由用户指定发送方式进行数据发送操作。

    ACTION_SENDTO:系统根据不同的Data类型,通过已注册的对应Application进行数据发送操作。

    ACTION_BOOT_COMPLETED:Android系统在启动完毕后发出带有此Action的广播(Broadcast)。 

    ACTION_TIME_CHANGED:Android系统的时间发生改变后发出带有此Action的广播(Broadcast)。 

    ACTION_PACKAGE_ADDED:Android系统安装了新的Application之后发出带有此Action的广播(Broadcast)。 

    ACTION_PACKAGE_CHANGED:Android系统中已存在的Application发生改变之后(如应用更新操作)发出带有此Action的广播(Broadcast)。 

    ACTION_PACKAGE_REMOVED:卸载了Android系统已存在的Application之后发出带有此Action的广播(Broadcast)。

Category:

     CATEGORY_DEFAULT:Android系统中默认的执行方式,按照普通Activity的执行方式执行。 

    CATEGORY_HOME:设置该组件为Home Activity。

    CATEGORY_PREFERENCE:设置该组件为Preference。 

    CATEGORY_LAUNCHER:设置该组件为在当前应用程序启动器中优先级最高的Activity,通常为入口ACTION_MAIN配合使用。 

    CATEGORY_BROWSABLE:设置该组件可以使用浏览器启动。 

    CATEGORY_GADGET:设置该组件可以内嵌到另外的Activity中。

Extras:

     EXTRA_BCC:存放邮件密送人地址的字符串数组。 

    EXTRA_CC:存放邮件抄送人地址的字符串数组。

    EXTRA_EMAIL:存放邮件地址的字符串数组。 

    EXTRA_SUBJECT:存放邮件主题字符串。 

    EXTRA_TEXT:存放邮件内容。 

    EXTRA_KEY_EVENT:以KeyEvent对象方式存放触发Intent的按键。  

    EXTRA_PHONE_NUMBER:存放调用ACTION_CALL时的电话号码。

Data:

     tel://:号码数据格式,后跟电话号码。 

    mailto://:邮件数据格式,后跟邮件收件人地址。

    smsto://:短息数据格式,后跟短信接收号码。

    content://:内容数据格式,后跟需要读取的内容。 

    file://:文件数据格式,后跟文件路径。

    market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。

        geo://latitude,longitude:经纬数据格式,在地图上显示经纬度指定的位置。

 

在intent-filter中指定data属性的实际目的是:要求接收的Intent中的data必须符合intent-filter中指定的data属性,这样达到反向限定Intent的作用。

例如:在AndroidManifest.xml中进行如下设置:

<activity android:name=".TestActivity">      <intent-filter>           <action android:name="com.ramon.test"/>           <data android:scheme="file"/>      </intent-filter>  </activity>  

那么启动该Activity的Intent必须进行如下设置:

Intent intent = new Intent();  Uri uri =  Uri.parse("file://com.android.test:520/mnt/sdcard");  intent.setData(uri);

data属性解析:

android:scheme、android:host、android:port、android:path、android:mimeType

 

data的前四个属性构成了URI的组成部分,mimeType设置了数据的类型

data元素组成的URI模型如下:

scheme://host:port/path

举例说明:

URI   file://com.android.jony.test:520/mnt/sdcard

scheme-->file:

host-->com.android.jony.test

port-->520

path-->mnt/sdcard

其中host和port为URI的authority,如果没有指定host,port将被忽略

data的各属性并不是独立的,data的各属性构成了URI的整个组成部分。要使authority(host和port)有意义,必须指定scheme;要使path有意义,必须使scheme和authority(host和port)有意义。

 

URI和intent-filter匹配:

Intent中URI和intent-filter进行比较的时候只会进行部分的比较:

(1)当intent-filter中只设置了scheme,只会比较URI的scheme部分;

(2)当intent-filter中只设置了scheme和authority,那么只会匹配URI中的scheme和authority;

(3)当intent-filter中设置了scheme、authority和path,那么只会匹配URI中的scheme、authority、path;(path可以使用通配符进行匹配)

(4)当intent-filter中设置了mimeType,还会进行数据类型的匹配。

 

(以下几点转自 http://www.cnblogs.com/xiaoxiaing/p/5807807.html)

1.当你在androidmanifest里面定义了一个或多个action时

你使用隐式意图其他activity或者service时,规定你隐式里面的action必须匹配XML中定义的action,可以只匹配XML文件一个就行

 

2.当你在androidmanifest里面定义了一个或多个category时

规定你的代码中可以没有category,但是XML中要加上"android.intent.category.DEFAULT"这句。如果你在代码中定义了一个或者多个category,那么你必须跟XML文件中定义的一样。比如你定义了一个category,那么要在XML文件中匹配到一个,,如果你定义了多个category,那么要在XML文件中全部匹配,一一对应!

 

3.当你在androidmanifest里面定义了一个或多个data时规定,要求intent中必须含有data数据,并且data数据能够完全匹配XML文件中的某一个data.这里需要注意的是XML文件中虽然没有指定URL,但是他默认的是"file和content"所以我们在代码中匹配要写成intent.setDataAndType(Uri.parse("file://abc"),"data数据");

 

如果同时都设置的action,category,data,那么必须都要完全匹配正确

 

注意:为了接收隐含意图,您必须在意图过滤器中包含CATEGORY_DEFAULT类别。方法startActivity()和startActivityForResult()将所有意图视为就像它们声明了CATEGORY_DEFAULT类别一样。如果您不在您的意图过滤器中声明它,则隐式意图将不会解析为您的活动。

 

 

在Activity中处理意图

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

例如:

@Overrideprotected 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 ...    }}

返回一个结果:

如果要将结果返回给调用的活动,只需调用setResult()来指定结果代码和结果Intent。 当您的操作完成并且用户应该返回到原始活动时,请调用finish()关闭(并销毁)您的活动。例如:

// Create intent to deliver some kind of result dataIntent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"));setResult(Activity.RESULT_OK, result);finish();

您必须给result 指定结果代码。 一般来说,它是RESULT_OK或RESULT_CANCELED。 然后,您可以根据需要向Intent提供其他数据。

注意:默认情况下,结果设置为RESULT_CANCELED。 因此,如果用户在完成操作之前按下“后退”按钮,并且在设置结果之前,原始活动将收到“已取消”的结果。

 

如果您只需返回一个指示多个结果选项之一的整数,就可以将结果代码设置为高于0的任何值。如果使用结果代码来传递一个整数,并且不需要包含Intent,那么可以调用setResult()并传递一个结果代码。例如:

setResult(RESULT_COLOR_RED);finish();

在这种情况下,可能只有少数可能的结果,因此结果代码是本地定义的整数(大于0)。当您将结果返回到您自己的应用程序中的一个活动时,这很好,因为接收结果的活动可以引用公共常量来确定结果代码的值。

 

注意:无需检查您的活动是否以startActivity()或startActivityForResult()开始。 如果启动您的活动的意图可能会期望结果,只需调用setResult()。如果始发活动已经调用了startActivityForResult(),那么系统将它提供给setResult()的结果; 否则,结果将被忽略。


Demo 地址








阅读全文
0 0
原创粉丝点击