13-3-31 Android中Intent做为中间件的重要

本文深入解析了Android中的Intent机制,介绍了其基本概念、组成部分及其在组件间通信中的作用。同时,文章列举了多种Intent应用场景示例,并通过便笺应用实例展示了Intent的定义与解析过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一个Android应用中,主要是由四种组件组成的,这四种组件可参考“Android应用的构成。而这四种组件(ActivityServiceBroadcast ReceiverContent Provider)是独立的,它们之间可以互相调用,协调工作,最终组成一个真正的Android应用。

在这些组件之间的通讯中,主要是由Intent协助完成的。

Intent负责对应用中一次操作的动作(Action)、动作涉及数据(Data)、附加数据进行描述或称作类别(Category),Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。

因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的桥梁。

例如,在一个联系人维护的应用中,当我们在一个联系人列表屏幕(假设对应的ActivitylistActivity)上,点击某个联系人后,希望能够跳出此联系人的详细信息屏幕(假设对应的ActivitydetailActivity)

为了实现这个目的,listActivity需要构造一个 Intent,这个Intent用于告诉系统,我们要做查看动作,此动作对应的查看对象是某联系人,然后调用startActivity (Intent intent)

将构造的Intent传入,系统会根据此Intent中的描述,到AndroidMainfest.xml中找到满足此Intent要求的Activity,系统会调用找到的 Activity,即为detailActivity,最终传入IntentdetailActivity则会根据此Intent中的描述,执行相应的操作。

一、抽象描述要描述什么

Android参考文档中,对Intent的定义是执行某操作的一个抽象描述(确实很抽象)。我们先来看看这里的抽象描述,到底描述了什么。

首先,是要执行的动作(action)的一个简要描述,如VIEW_ACTION(查看)EDIT_ACTION(修改)等,Android为我们定义了一套标准动作:

MAIN_ACTION

VIEW_ACTION

EDIT_ACTION

PICK_ACTION

GET_CONTENT_ACTION

DIAL_ACTION

CALL_ACTION

SENDTO_ACTION

ANSWER_ACTION

INSERT_ACTION

DELETE_ACTION

RUN_ACTION

LOGIN_ACTION

CLEAR_CREDENTIALS_ACTION

SYNC_ACTION

PICK_ACTIVITY_ACTION

WEB_SEARCH_ACTION

此外,我们还可以根据应用的需要,定义我们自己的动作,并可定义相应的Activity来处理我们的自定义动作。

其次,是执行动作要操作的数据(data),Android中采用指向数据的一个URI来表示,如在联系人应用中,一个指向某联系人的URI可能为:content://contacts/1

这种URI表示,通过 ContentURI这个类来描述,具体可以参考android.net.ContentURI类的文档。

以联系人应用为例,以下是一些action / data对,及其它们要表达的意图:

VIEW_ACTION content://contacts/1-- 显示标识符为"1"的联系人的详细信息

EDIT_ACTION content://contacts/1-- 编辑标识符为"1"的联系人的详细信息

VIEW_ACTION content://contacts/-- 显示所有联系人的列表

PICK_ACTION content://contacts/-- 显示所有联系人的列表,并且允许用户在列表中选择一个联系人,然后把这个联系人返回给父activity。例如:电子邮件客户端可以使用这个Intent,要求用户在联系人列表中选择一个联系人

另外,除了actiondata这两个重要属性外,还有一些附加属性: 

category(类别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。

type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

component(组件),指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如actiondata/typecategory进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。

extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。

总之,action、 data/typecategoryextras 一起形成了一种语言。

这种语言使系统能够理解诸如“查看某联系人的详细信息”之类的短语。

随着应用不断的加入到系统中,它们可以添加新的action、 data/typecategory来扩展这种语言。

应用也可以提供自己的Activity来处理已经存在的这样的“短语”,从而改变这些“短语”的行为。

二、Android如何解析Intent

在应用中,我们可以以两种形式来使用Intent

直接Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

对于直接IntentAndroid不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些间接Intent,通过解析,将 Intent映射给可以处理此IntentActivityIntentReceiverService

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intentactiontypecategory这三个属性来进行判断的,判断方法如下:

如果Intent指明定了action,则目标组件的IntentFilteraction列表中就必须包含有这个action,否则不能匹配;

如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。

如果Intent中的数据不是content: 类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme (比如 http: 或者mailto: ) 进行匹配。同上,Intent scheme必须出现在目标组件的scheme列表中。

如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。

三、系统自带Intent

1.google搜索内容

  Intent intent = new Intent();

  intent.setAction(Intent.ACTION_WEB_SEARCH);

  intent.putExtra(SearchManager.QUERY,"searchString")

  startActivity(intent);

2.浏览网页

  Uri uri = Uri.parse("http://www.google.com");

  Intent it = new Intent(Intent.ACTION_VIEW,uri);

  startActivity(it);

3.显示地图

  Uri uri = Uri.parse("geo:38.899533,-77.036476");

  Intent it = new Intent(Intent.Action_VIEW,uri);

  startActivity(it);

4.路径规划

  Uri uri = Uri.parse("http://maps.google.com/maps?" +

    "f=dsaddr=startLat startLng&daddr=endLat endLng&hl=en");

  Intent it = new Intent(Intent.ACTION_VIEW,URI);

  startActivity(it);

5.拨打电话

  Uri uri = Uri.parse("tel:xxxxxx");

  Intent it = new Intent(Intent.ACTION_DIAL, uri);

  startActivity(it);

6.调用发短信的程序

  Intent it = new Intent(Intent.ACTION_VIEW);

  it.putExtra("sms_body", "The SMS text");

  it.setType("vnd.android-dir/mms-sms");

  startActivity(it);

7.发送短信

  Uri uri = Uri.parse("smsto:0800000123");

  Intent it = new Intent(Intent.ACTION_SENDTO, uri);

  it.putExtra("sms_body", "The SMS text");

  startActivity(it);

  String body="this is sms demo";

  Intent mmsintent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("smsto", number, null));

  mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);

    mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, true);

  mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, true);

  startActivity(mmsintent);

8.发送彩信

  Uri uri = Uri.parse("content://media/external/images/media/23");

  Intent it = new Intent(Intent.ACTION_SEND);

  it.putExtra("sms_body", "some text");

  it.putExtra(Intent.EXTRA_STREAM, uri);

  it.setType("image/png");

  startActivity(it);

  StringBuilder sb = new StringBuilder();

  sb.append("file://");

  sb.append(fd.getAbsoluteFile());

  Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mmsto", number, null));

  // Below extra datas are all optional.

  intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_SUBJECT, subject);

  intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);

  intent.putExtra(Messaging.KEY_ACTION_SENDTO_CONTENT_URI, sb.toString());

  intent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, composeMode);

  intent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, exitOnSent);

  startActivity(intent);

9.发送Email

  Uri uri = Uri.parse("mailto:xxx@abc.com");

  Intent it = new Intent(Intent.ACTION_SENDTO, uri);

  startActivity(it);

  Intent it = new Intent(Intent.ACTION_SEND);

  it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");

  it.putExtra(Intent.EXTRA_TEXT, "The email body text");

  it.setType("text/plain");

  startActivity(Intent.createChooser(it, "Choose Email Client"));

  Intent it=new Intent(Intent.ACTION_SEND);

  String[] tos={"me@abc.com"};

  String[] ccs={"you@abc.com"};

  it.putExtra(Intent.EXTRA_EMAIL, tos);

  it.putExtra(Intent.EXTRA_CC, ccs);

  it.putExtra(Intent.EXTRA_TEXT, "The email body text");

    it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");

  it.setType("message/rfc822");

  startActivity(Intent.createChooser(it, "Choose Email Client"));

  Intent it = new Intent(Intent.ACTION_SEND);

  it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");

  it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");

  sendIntent.setType("audio/mp3");

  startActivity(Intent.createChooser(it, "Choose Email Client"));

10.播放多媒体

  Intent it = new Intent(Intent.ACTION_VIEW);

  Uri uri = Uri.parse("file:///sdcard/song.mp3");

  it.setDataAndType(uri, "audio/mp3");

  startActivity(it);

  Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");

  Intent it = new Intent(Intent.ACTION_VIEW, uri);

  startActivity(it);

11.uninstall apk

  Uri uri = Uri.fromParts("package", strPackageName, null);

  Intent it = new Intent(Intent.ACTION_DELETE, uri);

  startActivity(it);

12.install apk

  Uri installUri = Uri.fromParts("package", "xxx", null);

  returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);

13. 打开照相机

  Intent i = new Intent(Intent.ACTION_CAMERA_BUTTON, null);

  this.sendBroadcast(i);

  long dateTaken = System.currentTimeMillis();

  String name = createName(dateTaken) + ".jpg";

  fileName = folder + name;

  ContentValues values = new ContentValues();

  values.put(Images.Media.TITLE, fileName);

  values.put("_data", fileName);

  values.put(Images.Media.PICASA_ID, fileName);

  values.put(Images.Media.DISPLAY_NAME, fileName);

  values.put(Images.Media.DESCRIPTION, fileName);

  values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, fileName);

    Uri photoUri = getContentResolver().insert(

   MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

  Intent inttPhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

  inttPhoto.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);

    startActivityForResult(inttPhoto, 10);

14.gallery选取图片

  Intent i = new Intent();

  i.setType("image/*");

  i.setAction(Intent.ACTION_GET_CONTENT);

  startActivityForResult(i, 11);

15. 打开录音机

  Intent mi = new Intent(Media.RECORD_SOUND_ACTION);

  startActivity(mi);

16. 打开另一程序

  Intent i = new Intent();

  ComponentName cn = new ComponentName("com.yellowbook.android2",

         "com.yellowbook.android2.AndroidSearch");

    i.setComponent(cn);

    i.setAction("android.intent.action.MAIN");

    startActivityForResult(i, RESULT_OK);

四、应用例子

以下,以Android SDK中的便笺例子来说明,Intent如何定义及如何被解析。这个应用可以让用户浏览便笺列表、查看每一个便笺的详细信息。 

<manifest 

xmlns:android="http://schemas.android.com/apk/res/android" 

package="com.google.android.notepad"> 

<application 

android:icon="@drawable/app_notes" 

android:label="@string/app_name"> 

<provider 

class="NotePadProvider" 

android:authorities="com.google.provider.NotePad" 

/> 

<activity 

class=".NotesList" 

android:label="@string/title_notes_list"> 

     <intent-filter> 

       <action android:value="android.intent.action.MAIN"/> 

       <category android:value="android.intent.category.LAUNCHER"/> 

      </intent-filter> 

     <intent-filter> 

       <action android:value="android.intent.action.VIEW"/> 

       <action android:value="android.intent.action.EDIT"/> 

       <action android:value="android.intent.action.PICK"/> 

       <category android:value="android.intent.category.DEFAULT"/> 

       <type android:value="vnd.android.cursor.dir/vnd.google.note"/> 

      </intent-filter> 

     <intent-filter> 

       <action android:value="android.intent.action.GET_CONTENT"/> 

       <category android:value="android.intent.category.DEFAULT"/> 

       <type android:value="vnd.android.cursor.item/vnd.google.note"/> 

      </intent-filter> 

    </activity> 

  <activity class=".NoteEditor" android:label="@string/title_note"> 

     <intent-filter android:label="@string/resolve_edit"> 

       <action android:value="android.intent.action.VIEW"/> 

       <action android:value="android.intent.action.EDIT"/> 

       <category android:value="android.intent.category.DEFAULT"/> 

       <type android:value="vnd.android.cursor.item/vnd.google.note"/> 

      </intent-filter> 

     <intent-filter> 

       <action android:value="android.intent.action.INSERT"/> 

       <category android:value="android.intent.category.DEFAULT"/> 

       <type android:value="vnd.android.cursor.dir/vnd.google.note"/> 

      </intent-filter> 

    </activity> 

  <activity class=".TitleEditor" android:label="@string/title_edit_title" android:theme="@android:style/Theme.Dialog"> 

     <intent-filter android:label="@string/resolve_title"> 

       <action android:value="com.google.android.notepad.action.EDIT_TITLE"/> 

       <category android:value="android.intent.category.DEFAULT"/> 

       <category android:value="android.intent.category.ALTERNATIVE"/> 

       <category android:value="android.intent.category.SELECTED_ALTERNATIVE"/> 

       <type android:value="vnd.android.cursor.item/vnd.google.note"/> 

      </intent-filter> 

    </activity> 

</application> 

</manifest>

复制代码

例子中的第一个Activitycom.google.android.notepad.NotesList,它是应用的主入口,提供了三个功能,分别由三个 intent-filter进行描述:

1、第一个是进入便笺应用的顶级入口(actionandroid.app.action.MAIN)。类型为android.app.category.LAUNCHER表明这个Activity将在Launcher中列出。

2、第二个是,当typevnd.android.cursor.dir/vnd.google.note(保存便笺记录的目录)时,可以查看可用的便笺(actionandroid.app.action.VIEW),或者让用户选择一个便笺并返回给调用者(action为 android.app.action.PICK)。

3、第三个是,当typevnd.android.cursor.item/vnd.google.note时,返回给调用者一个用户选择的便笺(actionandroid.app.action.GET_CONTENT),而用户却不需要知道便笺从哪里读取的。有了这些功能,下面的 Intent就会被解析到NotesList这个activity

{ action=android.app.action.MAIN }:与此Intent匹配的Activity,将会被当作进入应用的顶级入口。

{ action=android.app.action.MAIN, category=android.app.category.LAUNCHER }:这是目前Launcher实际使用的 Intent,用于生成Launcher的顶级列表。

{ action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes }

显示"content://com.google.provider.NotePad/notes"下的所有便笺的列表,使用者可以遍历列表,并且察看某便笺的详细信息。

{ action=android.app.action.PICK data=content://com.google.provider.NotePad/notes }

显示"content://com.google.provider.NotePad/notes"下的便笺列表,让用户可以在列表中选择一个,然后将选择的便笺的 URL返回给调用者。

{action=android.app.action.GET_CONTENT type=vnd.android.cursor.item/vnd.google.note }:和上面的actionpickIntent类似,不同的是这个Intent允许调用者(在这里指要调用NotesList的某个 Activity)指定它们需要返回的数据类型,系统会根据这个数据类型查找合适的 Activity(在这里系统会找到NotesList这个Activity),供用户选择便笺。

第二个Activitycom.google.android.notepad.NoteEditor,它为用户显示一条便笺,并且允许 用户修改这个便笺。

它定义了两个intent-filter,所以具有两个功能。

第一个功能是,当数据类型为 vnd.android.cursor.item/vnd.google.note时,允许用户查看和修改一个便签(action为 android.app.action.VIEWandroid.app.action.EDIT)。

第二个功能是,当数据类型为 vnd.android.cursor.dir/vnd.google.note,为调用者显示一个新建便笺的界面,并将新建的便笺插入到便笺列表中(actionandroid.app.action.INSERT)。

      有了这两个功能,下面的Intent就会被解析到NoteEditor这个activity

{action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes/{ID}} :向用户显示标识为 ID的便笺。

{action=android.app.action.EDIT data=content://com.google.provider.NotePad/notes/{ID}}:允许用户编辑标识为ID的便笺。

{action=android.app.action.INSERT data=content://com.google.provider.NotePad/notes }:在“content://com.google.provider.NotePad/notes”这个便笺列表中创建一个新的空便笺,并允许用户编辑这个便签。当用户保存这个便笺后,这个新便笺的URI将会返回给调用者。

最后一个Activitycom.google.android.notepad.TitleEditor,它允许用户编辑便笺的标题。

它可以被实现为一个应用可以直接调用(在Intent中明确设置component属性)的类,不过这里我们将为你提供一个在现有的数据上发布可选操作的方法。

在这个 Activity的唯一的intent-filter中,拥有一个私有的action: com.google.android.notepad.action.EDIT_TITLE,表明允许用户编辑便笺的标题。

和前面的viewedit 动作一样,调用这个Intent 的时候,也必须指定具体的便笺(typevnd.android.cursor.item/vnd.google.note)。不同的是,这里显示和编辑的只是便笺数据中的标题。

      除了支持缺省类别(android.intent.category.DEFAULT),标题编辑器还支持另外两个标准类别: android.intent.category.ALTERNATIVE

android.intent.category.SELECTED_ALTERNATIVE

实现了这两个类别之后,其它 Activity就可以调用queryIntentActivityOptions(ComponentName, Intent[], Intent, int)查询这个Activity提供的action,而不需要了解它的具体实现;

或者调用addIntentOptions(int, int, ComponentName, Intent[], Intent, int, Menu.Item[])建立动态菜单。需要说明的是,在这个intent-filter中有一个明确的名称(通过android:label= "@string/resolve_title"指定),在用户浏览数据的时候,如果这个Activity是数据的一个可选操作,指定明确的名称可以为用户提供一个更好控制界面。

有了这个功能,下面的Intent就会被解析到TitleEditor这个Activity

{ action=com.google.android.notepad.action.EDIT_TITLE data=content://com.google.provider.NotePad/notes/{ID}}:显示并且允许用户编辑标识为ID的便笺的标题。

引用:http://bbs.hiapk.com/thread-7959-1-1.html

引用:http://blog.sina.com.cn/s/blog_613e4fea0100oirw.html

 

************************************************************************

飞扬小米(记)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值