Intent
Intent 是 Android 系统中贯穿四大组件(Activity、Service、BroadcastReceiver、ContentProvider)的通信媒介,本质是一种 “消息载体”,用于在组件间传递操作指令、数据和启动配置。它不仅支持同一应用内的组件交互,还能实现跨应用的组件调用,是理解 Android 组件化和通信机制的关键。
一、Intent 的核心定位与作用
Intent 的核心价值是解耦组件间的直接依赖—— 组件无需知道目标组件的具体实现,只需通过 Intent 声明 “要做什么”,由 Android 系统(如 ActivityManagerService)负责解析并找到对应的组件执行。其主要作用包括:
- 启动组件:启动 Activity(跳转页面)、启动 / 绑定 Service(后台任务)、发送 Broadcast(广播通知)。
- 传递数据:在启动组件时携带数据(如字符串、整数、序列化对象),支持组件间数据共享。
- 指定行为:通过 Action、Category 等参数,明确组件的执行动作(如 “拨打电话”“查看图片”)。
- 跨应用交互:调用其他应用的组件(如通过系统浏览器打开链接、调用相机拍照),实现应用间协作。
二、Intent 的两种类型:显式 Intent vs 隐式 Intent
根据是否明确指定目标组件,Intent 分为两种类型,适用场景完全不同:
对比维度显式 Intent(Explicit Intent)隐式 Intent(Implicit Intent)目标指定方式直接指定目标组件的全类名(包名 + 类名)不指定具体组件,通过 Action、Category、Data 描述 “动作”解析方式系统直接根据类名找到组件,无需匹配系统通过 “Intent 过滤器(Intent Filter)” 匹配符合条件的组件适用场景同一应用内的组件通信(如 App 内页面跳转)跨应用组件调用(如调用系统相机、浏览器)或同一应用内的 “松耦合” 交互安全性安全(仅本应用可调用,除非暴露组件权限)需注意安全(可能被其他应用拦截,Android 11+ 对跨应用隐式调用有限制)示例代码intent.setComponent(new ComponentName(pkg, cls))intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("https://www.baidu.com"))
关键补充:Intent 过滤器(Intent Filter)
隐式 Intent 依赖Intent Filter 匹配组件,组件需在 AndroidManifest.xml 中声明 Filter,系统通过 Filter 中的 action、category、data 三个维度匹配 Intent:
xml
<!-- 示例:Activity 声明隐式 Intent 过滤器,支持“查看链接” --><activity android:name=".WebActivity"><intent-filter><!-- 1. Action:指定组件支持的“动作”,如“查看”“拨打电话” --><action android:name="android.intent.action.VIEW" /><!-- 2. Category:指定组件的“场景类别”,默认需添加 DEFAULT 类别 --><category android:name="android.intent.category.DEFAULT" /><!-- 3. Data:指定组件支持的数据格式,如链接、文件类型 --><data android:scheme="https" /> <!-- 支持 https 协议的链接 --></intent-filter></activity>
- 匹配规则:Intent 需满足 Filter 中至少一个
action、所有category(默认包含DEFAULT)、且data格式匹配(如协议、MIME 类型)。
三、Intent 的核心属性
Intent 通过一系列属性描述 “要做什么” 和 “传递什么”,核心属性可分为行为属性(描述动作)和数据属性(传递信息)两类:
- 行为属性(描述动作与目标)
属性作用常用取值 / 方法示例Action定义组件要执行的 “动作”,是隐式 Intent 的核心匹配条件Intent.ACTION_VIEW(查看)、Intent.ACTION_CALL(打电话);设置方法:setAction(String action)Category补充描述动作的 “场景类别”,如 “默认场景”“桌面快捷方式”Intent.CATEGORY_DEFAULT(默认,隐式调用必加)、Intent.CATEGORY_LAUNCHER(应用入口);设置方法:addCategory(String category)Component显式指定目标组件的全类名(包名 + 类名),用于显式 Intent设置方法:setComponent(ComponentName component) 或 setClassName(String pkg, String cls)Flags控制组件的启动模式、栈管理、权限等(如 “清空任务栈”“新任务启动”)Intent.FLAG_ACTIVITY_NEW_TASK(新任务栈启动)、Intent.FLAG_ACTIVITY_CLEAR_TOP(清空栈顶);设置方法:addFlags(int flags)
- 数据属性(传递数据与配置)
属性作用常用方法示例Data传递 “数据 Uri”,通常与 Action 配合(如 ACTION_VIEW + 链接 Uri)设置方法:setData(Uri uri);获取方法:getData()Type指定 Data 的 MIME 类型(如 “image/jpeg”“text/plain”),辅助隐式匹配设置方法:setType(String type);若同时设置 Data 和 Type,需用 setDataAndType(Uri uri, String type)Extras传递键值对形式的 “扩展数据”(如字符串、整数、Parcelable 对象),是组件间数据传递的主要方式设置方法:putExtra(String key, Object value)(支持 putString/putInt 等);获取方法:getExtras() 或 getStringExtra(String key)ClipData传递 “剪贴板数据”,主要用于跨应用的数据共享(如长按复制粘贴、拖拽)设置方法:setClipData(ClipData clipData);Android 10+ 对跨应用数据传递有更严格的权限控制
四、Intent 的数据传递限制与解决方案
Intent 虽然支持数据传递,但存在大小限制和类型限制,这是面试高频考点:
- 大小限制:为什么不能传递大数据?
核心原因是 Intent 数据通过 Binder 传输,而 Binder 驱动的缓冲区默认大小有限(约 1MB):
- Binder 为每个进程分配的缓冲区是共享的,若 Intent 数据过大(如超过 100KB),会占用大量缓冲区,导致其他 Binder 通信(如组件启动、系统服务调用)失败,甚至触发
TransactionTooLargeException。 - 注意:不同 Android 版本的 Binder 缓冲区大小可能略有差异,但 “不建议传递大数据” 是通用原则。
- 类型限制:支持哪些数据类型?
Intent 的 Extras 仅支持 “可序列化” 或 “可跨进程传输” 的类型,主要包括:
- 基本数据类型(int、long、boolean、String 等);
- 基本数据类型的数组(int []、String [] 等);
- 实现
Parcelable接口的对象(Android 推荐,序列化效率高于Serializable); - 实现
Serializable接口的对象(Java 标准,效率较低,不推荐用于跨进程); - 其他特殊类型(如
Bundle、IBinder引用,但IBinder仅支持同一进程内传递)。
- 大数据传递的替代方案
若需传递大数据(如图片、大文件、复杂对象列表),可采用以下方案:
- 文件共享:将数据写入本地文件(如
getExternalFilesDir()下的文件),通过 Intent 传递文件路径,目标组件读取文件。 - ContentProvider:通过 ContentProvider 封装数据访问接口,目标组件通过
ContentResolver查询 / 获取数据,支持跨应用、大数据访问(如系统相册通过 ContentProvider 提供图片)。 - Binder 直接通信:通过 AIDL 定义接口,使用
ParcelFileDescriptor传递文件描述符(零拷贝,高效),适用于跨进程传递大文件。 - 全局缓存 / 数据库:将数据存入内存缓存(如
LruCache,仅同一进程)或数据库(如 Room),目标组件通过键值读取。
五、Intent 的常见应用场景
- 启动 Activity(页面跳转)
- 显式 Intent(同一应用内):
- java
- 运行
// 从 MainActivity 跳转到 DetailActivity,并传递数据Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("userId", 123); // 传递整数
intent.putExtra("userName", "Alice"); // 传递字符串startActivity(intent); // 启动 Activity
- 隐式 Intent(跨应用,如调用系统浏览器):
- java
- 运行
// 打开百度链接(系统会匹配支持 ACTION_VIEW + https 协议的组件,如浏览器)Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));// 确保有组件能处理该 Intent(避免崩溃)if (intent.resolveActivity(getPackageManager()) != null) {startActivity(intent);}
- 启动 / 绑定 Service
- 启动 Service(后台任务,不返回结果):
- java
- 运行
Intent intent = new Intent(this, MyService.class);
intent.putExtra("taskId", "task_001");startService(intent); // Android O+ 需用前台服务,避免后台服务被杀死
- 绑定 Service(跨进程通信,通过 AIDL):
- java
- 运行
// 绑定远程 Service,通过 ServiceConnection 接收 Binder 实例Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.remote", "com.example.remote.MyRemoteService"));bindService(intent, serviceConnection, BIND_AUTO_CREATE);
- 发送 Broadcast(广播通知)
- 发送普通广播(跨应用,需声明权限):
- java
- 运行
// 发送自定义广播,携带数据Intent intent = new Intent("com.example.action.CUSTOM_ACTION");
intent.putExtra("message", "Hello from Broadcast");// Android 8.0+ 隐式广播需指定包名(限制后台广播)
intent.setPackage("com.example.target");sendBroadcast(intent);
六、Intent 的安全注意事项
- 隐式 Intent 暴露风险:若组件声明了隐式 Intent Filter 且未限制权限,可能被其他应用恶意调用(如启动敏感 Activity)。解决方案:
- 对跨应用组件添加权限校验(如
android:permission); - Android 11+ 引入 “软件包可见性”,需在
AndroidManifest.xml中声明允许交互的应用包名: - xml
<queries><!-- 允许调用 com.example.browser 应用 --><package android:name="com.example.browser" /></queries>
- 对跨应用组件添加权限校验(如
- 数据传递安全:Intent 传递的数据会通过 Binder 传输,若包含敏感信息(如密码、token),需加密(如 AES 加密),避免被中间人窃取。
- 避免传递过大数据:如前所述,超过 100KB 的数据可能触发
TransactionTooLargeException,需用文件或 ContentProvider 替代。
七、核心总结
Intent 是 Android 组件通信的 “桥梁”,其核心特点可概括为:
- 两种类型:显式(指定组件,同应用)、隐式(描述动作,跨应用);
- 三大作用:启动组件、传递数据、指定行为;
- 关键限制:数据大小受 Binder 缓冲区限制(约 1MB),类型需支持序列化;
- 底层依赖:组件启动和数据传递均基于 Binder 机制,由
ActivityManagerService等系统服务调度。
理解 Intent 的设计逻辑和使用限制,是高效开发 Android 应用(尤其是组件化、跨应用交互场景)的基础,也是面试中高频考察的知识点。