Anroid中的Intent

1:什么是 Intent

Intent是对被执行操作的抽象描述。调用 startActivity(Intent),可以启动 Activity;调用 broadcastIntent(Intent),可以把 Intent 发送给任何相关的 IntentReceiver 组件;调用 startService(Intent, Bundle) 以及 bindService(Intent, String, ServiceConnection, int) 可以让应用和后台服务进行通信。

Intent 提供了一个在不同应用的代码之间进行晚绑定 (late runtime binding) 的机制。它主要被用来启动 Activities,因此可以被看作是 Activities 之间的粘合剂。 Intent  大体上是一个被动数据结构,该数据结构包括被执行动作的抽象描述。Intent 中的主要内容有:
ü          action -- 需要被执行的动作。比如 VIEW_ACTION, EDIT_ACTION, MAIN_ACTION 等。
ü          data -- 执行动作要操作的数据,在 Intent 里用指向数据记录的URI (ContentURI) 表示。比如联系人数据库中的一个联系人记录。
译注:被动数据结构:只能由外部线程或者进程改变的数据结构。与能够通过相关的线程或者进程执行内部操作从而产生外部行为的主动数据结构相对应。
下面是一些 action/data 对的例子:
ü          VIEW_ACTION content://contacts/1 -- 显示标识符为"1"的联系人的信息。
ü          EDIT_ACTION content://contacts/1 -- 编辑标识符为"1"的联系人的信息。
ü          VIEW_ACTION content://contacts/ -- 显示可遍历的联系人列表。这是用来进入联系人应用主界面(顶级入口,top-level entry)的典型方法。在这个界面中察看某个联系人会产生一个新的 Intent:{VIEW_ACTION content://contacts/N},用来启动新的Activity,显示该联系人的详细信息。
ü          PICK_ACTION content://contacts/ -- 先是可遍历的联系人列表,并且允许用户在列表中选择一个联系人,然后把这个联系人返回给"上级活动"(parent activity)。例如:电子邮件客户端可以使用这个 Intent,要求用户在联系人列表中选择一个联系人。
除了 action, data 两个主要属性,Intent 还具有一些其它属性,这些属性也可以被用在Intent 里:
category -- 类别,被执行动作的附加信息。 例如  LAUNCHER_CATEGORY  表示 Intent  的接受者应该在  Launcher  中作为顶级应用出现;而 ALTERNATIVE_CATEGORY 表示当前的 Intent 是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。
type -- 数据类型,显式指定 Intent 的数据类型 (MIME)。一般上 Intent 的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
component -- 组件,为使用 Intent 的组件类指定名称。通常会根据 Intent 中包含的其它信息 —— 比如 action, data/type, categories —— 进行查找,最终找到一个与之匹配的组件。如果这个属性存在的话,将直接使用它指定的组件,不再执行上述查找过程。指定了这个属性以后,Intent 的其它所有属性都是可选的。
extras -- 额外的附加信息,是其它所有附加信息的集合。使用 extras 可以为组件提供扩展信息,比如,如果要发送电子邮件,也就是要执行“发送电子邮件”的动作,可以将电子邮件的标题、正文等保存在 extras 里。
在 Intent 类里定义了多种标准 action 和 category 常量(字符串),同时应用也可以根据自己的需要进行定义。这些字符串使用 JAVA 风格的 scoping,从而保证它们的唯一性。比如标准 VIEW_ACTION 的定义是 “android.app.action.VIEW”。
概括而言,“动作”、“数据类型”、“类别”(译注:Intent的action类 型)和“附加数据”一起形成了一种语言。这种语言使得系统能够理解诸如“打john的手机”之类的短语。随着应用不断的加入到系统中,它们可以添加新的“ 动作”、“数据类型”、“类别”来扩展这种语言。应用也可以提供自己的 activities 来处理已经存在的“短语”,从而改变这些“短语”的行为。
 
 2解析Intent
Intent 有两种主要形式:
ü          显式意图(直接意图?)。 显式意图是指定了  component  属性的  intents 。调 用 setComponent(ComponentName) 或者 setClass(Context, Class) 可以为 intents 设定 component 属性 —— 指定具体的组件类。这些 intents 一般不包括包括其它任何信息,它们通常只是用来通知应用启动内部的 activities 作为该应用的(当前)用户界面。
ü          隐式意图(含蓄意图?)。隐式意图是没有指明 comonent 的 intents。这些 intents 必须包括足够的信息,这样系统才能确定在所有的可用组件中,对一个 intent 来说运行哪一个组件才是最合适的。
在使用 implicit intents 的时候,对于一个任意的 intent,我们需要知道用它来做什么。“Intent 解析过程”用来处理这个问题。“Intent 解析过程”将 intent 映射到可以处理它的 activity, IntentReceiver 或者 service。
Intent 解析机制主要是将已安装应用程序包里的 Intent-Filter 描述和 Intent 进行匹配。如果使用广播发送 Intent,还要在已经注册的 IntentReceiver 中尽心匹配。更多的相关描述可以在 IntentFilter 中找到。
在解析  Intent  的过程中要用到  Intent  的三个属性:动作、数据类型和类别。使用这些属性,就可以 PackageManager 上查询能够处理当前 intent 的合适组件。组件是否合适由 AndroidManifest.xml 文件中提供的 intent 信息决定。判断的方法如下:
1、如果 intent 指明了要执行的 action,组件 action 列表中就必须包含着个 action,否则不能匹配;
2、如果 Intent 没有提供数据类型 (type),系统从数据 (data) 中得到数据类型。和 action 一样,组件的数据类型列表中必须包含 intent 的数据类型,否则不能匹配。
3、如果 Intent 中的数据不是 content: 类型的 URL,而且 Intent 也没有明确指定它的数据类型,将根据 Intent 中数据的 scheme (比如 http: or  mailto:) 进行匹配。同上,Intent 的 scheme 必须出现在组件的 scheme 列表中。
4、如果 Intent 指定了一个或多个类别,这些类别必须全部出现在组建的类别列表中。比如 intent 中包含了两个类别:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的组件必须至少包含这两个类别。
以一个应用实例作为例子,这个应用可以让用户浏览便笺列表、查看每一个便笺的详细信息:
<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>
 
例子中的第一个 activity 是 com.google.android.notepad.NotesList。它是进入应用的主入口(main entry),具有三种功能,分别由三个 intent 模板进行描述。
1、第一个功能是进入便笺应用的顶级入口。它的类型是 android.app.category.LAUNCHER,说明这个应用应该在 Launcher 中被列出。
2、第二个功能用来浏览可用的便笺,或者让用户选择一个特定的便笺并且把这个便 笺返回给调用者。当数据类型是 vnd.android.cursor.dir/vnd.google.note (便笺记录的目录) 的时候,执行动作 android.app.action.VIEW 可以浏览可用的便笺;执行动作 android.app.action.PICK 可以让用户选择便笺。
3、第三个功能返回给调用者一个用户选择的便笺。当数据类型是 vnd.android.cursor.dir/vnd.google.note 的时候,执行动作 android.app.action.GET_COUTENT 调用者不需要知道
有了这些功能,就能够将下列 intents 匹配到 NotesList 的 activity:
{ action=android.app.action.MAIN }. 如果 activities 能够被用作进入应用的顶级入口,就可以和这个 intent 进行匹配。
{ action=android.app.action.MAIN, category=android.app.category.LAUNCHER }. 这是目前 Launcher 实际使用的 intent,构成了它的顶级列表。
问题:怎么构成??
{ 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 }. 这个 intent 和上面的 pick 动作类似,不同的是这个 intent 允许调用者(仅仅)指定它们需要的数据类型(,而不需要了解数据存放的详细位置,即数据的 URI)。系统根据这个数据类型选择恰当的 activity,然后让用户选择某些数据。
 
第二个 activity 是 com.google.android.notepad.NoteEditor,它为用户显示一个单独的便笺,并且允许用户对这个便笺进行修改。 它具有两个  intent  模板,所以具有两个功能。第 一个操作是主要的操作,允许用户察看和编辑一个便签(执行 android.app.action.VIEW 和 android.app.action.EDIT 动作,数据类型是 vnd.android.cursor.item/vnd.google.note)。第二个模板可以让调用者显示创建新便笺的用户界面,并且将新便笺插 入到便笺列表中(执行 android.app.action.INSERT 动作,数据类型是 vnd.android.cursor.dir/vnd.google.note)。
有了这两个功能,下列 intents 就能够匹配到 NotesList 的 activity:
{ action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes/{ID} } 向用户显示标识为 ID 的便笺。将标识为 ID 的便笺缩写为 note{ID},下同。
{ action=android.app.action.EDIT data=content://com.google.provider.NotePad/notes/{ID} } 让用户能够编辑 notes{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 模板,它具有一个私有 action: com.google.android.notepad.action.EDIT_TITLE,允许用户编辑便笺的标题。和前面的 view 和 edit 动作一样,调用这个 intent 的时候,也必须指定具体的便笺。不一样的是,这里显示和编辑的只是便笺数据中的标题。
除了支持确省类别 (default category, android.intent.category.DEFAULT,原文是 android.intent.category.VIEW,有误),标题编辑器还支持另外两个标准类 别:android.intent.category.ALTERNATIVE 和 android.intent.category.SELECTED_ALTERNATIVE。实现了这两个类别之后,其它 activities 可以调用函数 queryIntentActivityOptions(ComponentName, Intent[], Intent, int) 查询这个 activity 支持的 actions,而不需要了解它的具体实现;或者调用 addIntentOptions(int, int, ComponentName, Intent[], Intent, int, Menu.Item[]) 建立动态菜单。需要说明的是, 这个  intent  模板有一个明确的名称(通过  android:label="@string/resolve_title"  指定)。在用户浏览数据的时候, 如果这个  activity  是数据的一个可选操作,指定明确的名称可以为用户提供一个更好控制界面。  有了这个功能,下列  intents  就能够匹配到  NotesList  的  activity :     {action=com.google.android.notepad.action.EDIT_TITLE data=content://com.google.provider.NotePad/notes/{ID} }  显示并且允许用户编辑  note{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` 压缩多个数据字段 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值