Android中的Intent

Intent详解
本文详细介绍了Android应用中Intent的使用原理,包括其如何描述组件间的交互、Android系统如何解析Intent以及具体的实例解析。
        在一个Android应用中,主要是由四种组件组成的,这四种组件可参考“ Android应用的构成”。 而这四种组件是独立的,它们之间可以互相调用,协调工作,最终组成一个真正的Android应用。在这些组件之间的通讯中,主要是由Intent协助完成的。Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调 用者之间的解耦。
        例如,在一个联系人维护的应用中,当我们在一个联系人列表屏幕(假设对应的Activity为listActivity)上,点击某个联系人后,希望能够 跳出此联系人的详细信息屏幕(假设对应的Activity为detailActivity),为了实现这个目的,listActivity需要构造一个 Intent,这个Intent用于告诉系统,我们要做“查看”动作,此动作对应的查看对象是“某联系人”,然后调用startActivity (Intent intent),将构造的Intent传入,系统会根据此Intent中的描述,到ManiFest中找到满足此Intent要求的Activity,系 统会调用找到的Activity,即为detailActivity,最终传入Intent,detailActivity则会根据此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,要求用户在联系人列表中选择一个联系人

         另外,除了action和data这两个重要属性外,还有一些附加属性:
  • category(类别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这 些动作可以在同一块数据上执行。
  • type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
  • component(组件),指定Intent的的目标组件的类名称。通常Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。
  • extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。

         总之,action、data/type、category和extras 一起形成了一种语言。这种语言使系统能够理解诸如“查看某联系人的详细信息”之类的短语。随着应用不断的加入到系统中,它们可以添加新的action、 data/type、category来扩展这种语言。应用也可以提供自己的Activity来处理已经存在的这样的“短语”,从而改变这些“短语”的行 为。

二、Android如何解析Intent
        在应用中,我们可以以两种形式来使用Intent:
  • 直接Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。
  • 间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。
        对于直接Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些间接Intent,通过解析,将 Intent映射给可以处理此Intent的Activity、IntentReceiver或Service。
        Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找 到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的,判断方 法如下:
  • 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个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,解析得到的目标组件必须至少包含这两个类别。

三、应用例子
        以下,以Android SDK中的便笺例子来说明,Intent如何定义及如何被解析。这个应用可以让用户浏览便笺列表、查看每一个便笺的详细信息。
xml 代码
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2. package="com.google.android.notepad">
  3.    <application android:icon="@drawable/app_notes"
  4. android:label="@string/app_name">

  5.    <provider class="NotePadProvider"
  6. android:authorities="com.google.provider.NotePad" />

  7.    <activity class=".NotesList" android:label="@string/title_notes_list">
  8.      <intent-filter>
  9.        <action android:value="android.intent.action.MAIN" />
  10.        <category android:value="android.intent.category.LAUNCHER" />
  11.      </intent-filter>
  12.      <intent-filter>
  13.        <action android:value="android.intent.action.VIEW" />
  14.        <action android:value="android.intent.action.EDIT" />
  15.        <action android:value="android.intent.action.PICK" />
  16.        <category android:value="android.intent.category.DEFAULT" />
  17.        <type android:value="vnd.android.cursor.dir/vnd.google.note" />
  18.      </intent-filter>
  19.      <intent-filter>
  20.        <action android:value="android.intent.action.GET_CONTENT" />
  21.        <category android:value="android.intent.category.DEFAULT" />
  22.        <type android:value="vnd.android.cursor.item/vnd.google.note" />
  23.      </intent-filter>
  24.    </activity>

  25.    <activity class=".NoteEditor" android:label="@string/title_note">
  26.      <intent-filter android:label="@string/resolve_edit">
  27.        <action android:value="android.intent.action.VIEW" />
  28.        <action android:value="android.intent.action.EDIT" />
  29.        <category android:value="android.intent.category.DEFAULT" />
  30.        <type android:value="vnd.android.cursor.item/vnd.google.note" />
  31.      </intent-filter>
  32.      <intent-filter>
  33.        <action android:value="android.intent.action.INSERT" />
  34.        <category android:value="android.intent.category.DEFAULT" />
  35.        <type android:value="vnd.android.cursor.dir/vnd.google.note" />
  36.      </intent-filter>
  37.    </activity>

  38.    <activity class=".TitleEditor" android:label="@string/title_edit_title"
  39. android:theme="@android:style/Theme.Dialog">
  40.      <intent-filter android:label="@string/resolve_title">
  41.        <action android:value="com.google.android.notepad.action.EDIT_TITLE" />
  42.        <category android:value="android.intent.category.DEFAULT" />
  43.        <category android:value="android.intent.category.ALTERNATIVE" />
  44.        <category android:value="android.intent.category.SELECTED_ALTERNATIVE" />
  45.        <type android:value="vnd.android.cursor.item/vnd.google.note" />
  46.      </intent-filter>
  47.    </activity>

  48. </application>
  49. </manifest>
        例子中的 第一个Activity 是com.google.android.notepad.NotesList,它是应用的主入口,提供了三个功能,分别由三个 intent-filter进行描述:
        1、第一个是进入便笺应用的顶级入口(action为android.app.action.MAIN)。类型为android.app.category.LAUNCHER表明这个Activity将在Launcher中列出。
        2、第二个是,当type为vnd.android.cursor.dir/vnd.google.note(保存便笺记录的目录) 时,可以查看可用的便笺(action为android.app.action.VIEW),或者让用户选择一个便笺并返回给调用者(action为 android.app.action.PICK)。
        3、第三个是,当type为vnd.android.cursor.item/vnd.google.note时,返回给调用者一个用户选择的便笺(action为android.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 }:和 上面的action为pick的Intent类似,不同的是这个Intent允许调用者(在这里指要调用NotesList的某个Activity)指定 它们需要返回的数据类型,系统会根据这个数据类型查找合适的 Activity(在这里系统会找到NotesList这个Activity),供用户选择便笺。


        第二个Activity是com.google.android.notepad.NoteEditor,它为用户显示一条便笺,并且允许 用户修改这个便笺。它定义了两个intent-filter,所以具有两个功能。第一个功能是,当数据类型为 vnd.android.cursor.item/vnd.google.note时,允许用户查看和修改一个便签(action为 android.app.action.VIEW和android.app.action.EDIT)。第二个功能是,当数据类型为 vnd.android.cursor.dir/vnd.google.note,为调用者显示一个新建便笺的界面,并将新建的便笺插 入到便笺列表中(action为android.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将会返回给调用者。


        最后一个Activity是com.google.android.notepad.TitleEditor,它允许用户编辑便笺的标题。它可以被实现为 一个应用可以直接调用(在Intent中明确设置component属性)的类,不过这里我们将为你提供一个在现有的数据上发布可选操作的方法。在这个 Activity的唯一的intent-filter中,拥有一个私有的action: com.google.android.notepad.action.EDIT_TITLE,表明允许用户编辑便笺的标题。和前面的view和edit 动作一样,调用这个Intent 的时候,也必须指定具体的便笺(type为vnd.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的便笺的标题。
<think> 嗯,用户这次明确要求了解Android开发中的Intent相关知识,并引用了四篇站内资料作为补充参考。从引用内容看,用户需要的是系统性的概念解析而非碎片化信息,尤其关注使用方法和底层原理的结合说明。 用户此前对NLP中intent的提问和当前Android intent的询问形成有趣对比——虽然术语相同,但NLP的意图识别是AI领域的抽象概念,而Android Intent是具体的编程机制。这种跨领域术语复用可能需要特别说明以避免混淆。 根据引用材料的关键信息点: - 引用[1]强调IntentAndroid组件化解耦设计中的核心地位 - 引用[2]精确定义了Intent作为通信中介的本质 - 引用[3]揭示了隐式IntentIntent Filter的匹配机制 - 引用[4]带出对象传递的实用需求 需要构建分层知识框架:先建立基础概念认知(显式/隐式区别),再深入通信机制(匹配原理),最后补充高阶用法(对象传递)。特别要注意引用[3]提到的PackageManagerService底层机制,这是很多开发者容易忽略的关键点。 对于原理部分,准备用双元结构图解法:既展示用户可见的API调用流程(如startActivity()),又同步揭示系统内部发生的匹配过程(IntentResolver查询)。对象传递方案要强调Parcelable与Serializable的性能差异,这是实际开发中的常见陷阱。 考虑到用户可能面临的真实开发场景,在代码示例中加入典型错误示范(如忘记android:exported导致的隐式调用失败)会更有实践价值。最后的技术栈建议需保持开放性,既要提及当前主流方案(如ViewModel+LiveData),也要说明传统方式(Bundle)的适用场景。 </think> 以下是关于 Android 开发中 Intent 的详细解析,结合核心原理与实践方法: --- ### 一、Intent 的本质与作用 1. **组件通信媒介** IntentAndroid 四大组件(Activity/Service/BroadcastReceiver/ContentProvider)间的通信桥梁,实现跨组件解耦[^2]。 - 显式 Intent:**直接指定目标组件类名** ```java Intent intent = new Intent(MainActivity.this, DetailActivity.class); startActivity(intent); ``` - 隐式 Intent:**通过动作(Action)和数据(Data)匹配目标** ```java Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com")); startActivity(intent); ``` 2. **核心功能** - 启动组件(如跳转页面、启动服务) - 传递数据(支持基本类型及对象) - 广播事件(如系统电量低通知) --- ### 二、Intent 的底层原理 #### 隐式 Intent 匹配机制[^3] $$ \text{匹配流程} = \begin{cases} \text{Action 匹配} & \text{(必须声明)} \\ \text{Data 匹配} & \text{(URI 和 MIME 类型)} \\ \text{Category 匹配} & \text{(需兼容目标声明)} \end{cases} $$ ```mermaid graph LR A[隐式Intent] --> B{PackageManagerService} B --> C[查询所有 Intent-Filter] C --> D[匹配 Action/Data/Category] D --> E[返回符合条件的组件列表] ``` #### 关键组件: 1. **Intent Filter** 在 `AndroidManifest.xml` 中声明组件能力: ```xml <activity android:name=".WebActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="www.example.com" /> </intent-filter> </activity> ``` 2. **匹配失败排查** - 检查 `Action` 是否在目标 Filter 中声明 - 验证 `Data` 的 scheme/host/mimeType 是否一致 - 确认目标组件的 `android:exported="true"`(跨应用时必需) --- ### 三、数据传递高阶用法 #### 传递对象(需实现序列化)[^4] ```java // 自定义对象实现 Parcelable(高效替代 Serializable) public class User implements Parcelable { private String name; private int age; // Parcelable 接口实现(省略具体代码) ... } // 传递对象 Intent intent = new Intent(this, DetailActivity.class); intent.putExtra("user_data", new User("Alice", 25)); ``` #### 对比两种序列化: | **特性** | `Parcelable` | `Serializable` | |----------------|----------------------|---------------------| | 效率 | 高(内存直接读写) | 低(反射+IO) | | 实现复杂度 | 需手动编写代码 | 自动实现 | | 适用场景 | Android 组件间传递 | 网络传输/存储 | --- ### 四、最佳实践与常见问题 1. **选择启动模式** 通过 `Intent.setFlags()` 控制 Activity 栈,如: - `Intent.FLAG_ACTIVITY_NEW_TASK`:创建新任务栈 - `Intent.FLAG_ACTIVITY_CLEAR_TOP`:清除栈顶以上页面 2. **安全风险防范** - 接收 Intent 时校验数据合法性 - 敏感数据传递使用 `Intent.FLAG_GRANT_READ_URI_PERMISSION` 3. **性能优化** - 避免传递超过 1MB 的数据(用 `ContentProvider` 替代) - 使用 `Bundle` 压缩多个数据字段 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值