目录
[一、Intent 概述](#一、Intent 概述)
[二、Intent 的类型(显式和隐式)](#二、Intent 的类型(显式和隐式))
[1.显式 Intent](#1.显式 Intent)
[2.隐式 Intent](#2.隐式 Intent)
[三、Intent 的核心组成部分](#三、Intent 的核心组成部分)
[1. Action(动作)](#1. Action(动作))
[2. Data(数据)](#2. Data(数据))
[四、Intent Filter(意图过滤器)](#四、Intent Filter(意图过滤器))
[1.使用 putExtra() 方法逐个添加](#1.使用 putExtra() 方法逐个添加)
[2. 使用 Bundle 对象打包数据](#2. 使用 Bundle 对象打包数据)
[3. 传递数组和集合](#3. 传递数组和集合)
[六、使用 Intent 传递复杂数据](#六、使用 Intent 传递复杂数据)
[1.传递 Parcelable 对象(性能更高)](#1.传递 Parcelable 对象(性能更高))
[2.传递 Serializable 对象(更简单,但性能较差)](#2.传递 Serializable 对象(更简单,但性能较差))
[七、获取 Activity 的结果:startActivityForResult](#七、获取 Activity 的结果:startActivityForResult)
一、Intent 概述
Intent(意图)是 Android 程序中在不同组件之间(如 Activity、Service、BroadcastReceiver)传递消息的对象。它可以在运行时绑定不同的组件,是组件间通信的核心。
主要作用:
-
启动组件:启动一个 Activity、Service 或发送一个 Broadcast。
-
传递数据:在组件之间携带数据。
-
声明目标组件:可以明确指定要启动的组件,也可以只描述要执行的动作,由系统来选择合适的组件。
- startActivity (Intent)/startActivityForResult(Intent):来启动一个Activity
- startService (Intent)/bindService(Intent):来启动一个Service
- sendBroadcast:发送广播到指定BroadcastReceiver
二、Intent 的类型(显式和隐式)
1.显式 Intent
- 定义 :明确指定了要启动的组件类名(
Activity.class
,Service.class
)。通常用于启动应用内的组件,因为你知道具体的类名。 - 核心属性 :
ComponentName
。
java
// 启动同一个应用内的 AnotherActivity
Intent explicitIntent = new Intent(MainActivity.this, AnotherActivity.class);
startActivity(explicitIntent);
// 或者通过 setComponent 方法
Intent intent = new Intent();
intent.setComponent(new ComponentName(MainActivity.this, "com.example.app.AnotherActivity"));
startActivity(intent);
// 启动一个 Service
Intent serviceIntent = new Intent(MainActivity.this, MyService.class);
startService(serviceIntent);

- 系统处理: 系统不进行解析,直接启动指定的组件 。如果该组件存在且声明在Manifest中,则启动;否则抛出
ActivityNotFoundException
或类似异常。
2.隐式 Intent
- 定义 :不指定具体的组件类名,而是声明一个要执行的动作(Action),并附加一些数据(Data)、类别(Category)等信息。系统会根据这些信息在所有应用的 AndroidManifest.xml 中注册的**
<intent-filter>
**进行匹配,找到并启动最适合的组件。 - 核心属性 :
Action
,Data
,Category
,Type
,Extras
(用于传额外数据)等。
java
// 打开一个网页
Intent implicitIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
startActivity(implicitIntent);
// 发送邮件
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse("mailto:contact@example.com"));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "邮件主题");
startActivity(emailIntent);
// 分享文本
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "这是要分享的文本");
startActivity(Intent.createChooser(shareIntent, "分享到"));
- 系统处理:
- 查询PackageManager: 系统向
PackageManager
查询所有已安装应用的AndroidManifest.xml
文件。- 匹配
<intent-filter>
: 对于每个组件(Activity/Service/BroadcastReceiver)声明的<intent-filter>
,系统尝试匹配Intent的内容:
- Action: Intent的**Action必须在filter声明的
<action>
**列表中。- Data: Intent的Data (
Uri
&MIME Type
) 必须匹配filter声明的<data>
元素。Uri
匹配Scheme, Host, Port, Path;Type
匹配或*/*
通配。- Category: Intent携带的所有Category必须在filter声明的
<category>
列表中(filter可以声明额外的Category)。CATEGORY_DEFAULT
通常需要显式声明在filter中。- 过滤结果: 所有满足上述条件的组件被筛选出来。
- 选择目标:
- Activity/Service: 如果有多个匹配项,系统通常会显示一个选择器对话框(Resolver Activity) 让用户选择(除非设置了
Intent.createChooser()
强制显示,或设置了Intent.FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
等特殊标志,或目标应用设置了android:autoVerify="true"
并通过了App Links验证)。- BroadcastReceiver: 所有匹配的Receiver都会收到广播(有序广播按优先级顺序)。
三、Intent 的核心组成部分
一个 Intent 对象包含了许多信息,系统根据这些信息来决定哪个组件应该被启动。
1. Action(动作)
一个字符串,表示要执行的通用动作。例如:
-
Intent.ACTION_VIEW
: 显示数据给用户。 -
Intent.ACTION_EDIT
: 编辑数据。 -
Intent.ACTION_DIAL
: 拨号。 -
Intent.ACTION_SEND
: 发送数据(分享)。 -
Intent.CUSTOM_ACTION
: 也可以使用自定义的 Action 字符串。例如com.google.app.myapp.CUSTOM_ACTION,

2. Data(数据)
数据通常与 Action 配合使用,用**Uri
对象**表示要操作的数据。
-
ACTION_VIEW
+content://contacts/people/1
: 显示 ID 为 1 的联系人信息。 -
ACTION_EDIT
+file://sdcard/example.txt
: 编辑 SD 卡上的文本文件。 -
ACTION_CALL
+tel:123456
: 直接呼叫号码(需要CALL_PHONE
权限)。
3.Type(数据类型)
指定 Data 所指向数据的 MIME 类型。如果设置了 Type,系统通常会忽略 Data 中的 URI 的 MIME 类型推断。
java
intent.setType("image/png");
// 注意:setData 和 setType 会互相清除对方,所以如果要同时设置,请使用 setDataAndType
intent.setDataAndType(imageUri, "image/png");

4.Category(类别)
一个字符串,提供了关于目标组件的额外信息。一个 Intent 可以添加多个 Category。
-
Intent.CATEGORY_LAUNCHER
: 表示该 Activity 是任务的初始 Activity,会出现在应用启动器中。 -
Intent.CATEGORY_DEFAULT
: 如果希望组件能够被隐式 Intent 启动,通常需要声明这个 Category。 -
Intent.CATEGORY_BROWSABLE
: 表示目标 Activity 允许本身被浏览器启动。

5.Extras(附加数据)
以键值对形式存放的额外信息,用于在组件间传递数据。使用 putExtra()
方法添加。
-
系统定义了很多
EXTRA_*
常量,如Intent.EXTRA_EMAIL
,Intent.EXTRA_STREAM
。 -
也可以使用自定义的键。
java
// 传递数据
intent.putExtra("KEY_NAME", "Alice");
intent.putExtra("KEY_AGE", 25);
// 在目标 Activity 中获取
String name = getIntent().getStringExtra("KEY_NAME");
int age = getIntent().getIntExtra("KEY_AGE", 0); // 0 是默认值

6.Flags(标志)
用于指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务)以及启动之后如何对待它。这个后面说 Activity 的时候会详细讲解。
-
Intent.FLAG_ACTIVITY_NEW_TASK
: 在一个新任务中启动 Activity。 -
Intent.FLAG_ACTIVITY_CLEAR_TOP
: 如果目标 Activity 已在当前任务中运行,则不会启动该 Activity 的新实例,而是会清除其上的所有其他 Activity,并将其置于任务顶部。 -
Intent.FLAG_ACTIVITY_SINGLE_TOP
: 如果要启动的 Activity 是当前 Activity(位于返回栈的顶部),则不会创建新实例。

四、Intent Filter(意图过滤器)
为了让一个组件(如 Activity)能够响应特定的隐式 Intent,必须在 AndroidManifest.xml
中为该组件声明 <intent-filter>
。
一个 <intent-filter>
可以定义:
-
<action>
: 至少一个,声明组件能响应的动作。 -
<category>
: 零个或多个,声明组件所属的类别。如果没有指定类别,则只响应没有类别的 Intent。但CATEGORY_DEFAULT
几乎总是需要。 -
<data>
: 零个或多个,声明组件能处理的数据类型和 URI 模式。
示例:一个 Activity 声明自己可以处理"分享"动作和文本类型。
XML
<activity android:name=".ShareActivity">
<intent-filter>
<!-- 指定动作 -->
<action android:name="android.intent.action.SEND" />
<!-- 指定类别,使其能被隐式 Intent 启动 -->
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定数据类型 -->
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
五、Intent传递简单数据
1.使用 putExtra() 方法逐个添加
java
// 发送数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("name", "张三");
intent.putExtra("age", 25);
intent.putExtra("score", 95.5f);
intent.putExtra("isStudent", true);
startActivity(intent);
// 接收数据
Intent intent = getIntent();
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 0); // 第二个参数为默认值
float score = intent.getFloatExtra("score", 0.0f);
boolean isStudent = intent.getBooleanExtra("isStudent", false);
2. 使用 Bundle 对象打包数据
java
// 发送数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name", "李四");
bundle.putInt("age", 30);
bundle.putDouble("salary", 8000.50);
bundle.putBoolean("isEmployed", true);
intent.putExtras(bundle);
startActivity(intent);
// 接收数据
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
String name = bundle.getString("name");
int age = bundle.getInt("age");
double salary = bundle.getDouble("salary");
boolean isEmployed = bundle.getBoolean("isEmployed");
}
3. 传递数组和集合
java
// 发送数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
// 基本类型数组
intent.putExtra("intArray", new int[]{1, 2, 3, 4, 5});
intent.putExtra("stringArray", new String[]{"A", "B", "C"});
// ArrayList
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Kotlin");
list.add("Dart");
intent.putStringArrayListExtra("languageList", list);
startActivity(intent);
// 接收数据
int[] intArray = getIntent().getIntArrayExtra("intArray");
String[] stringArray = getIntent().getStringArrayExtra("stringArray");
ArrayList<String> languageList = getIntent().getStringArrayListExtra("languageList");
六、使用 Intent 传递复杂数据
除了基本类型,还可以通过 Intent 传递可序列化(Serializable)或可打包(Parcelable)的对象。类似bitmap默认实现Parcelable接口,直接传递即可
1.传递 Parcelable 对象(性能更高)
-
让你的类实现
Parcelable
接口。 -
实现
describeContents()
和writeToParcel(Parcel dest, int flags)
方法。 -
创建一个名为 **
CREATOR
**的静态字段。
java
public class User implements Parcelable {
private String name;
private int age;
// ... 构造方法、getter/setter ...
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
}
4.传递和接收:
java
// 发送方
User user = new User("Bob", 30);
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("user_key", user);
startActivity(intent);
// 接收方
User receivedUser = getIntent().getParcelableExtra("user_key");
通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射 成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面, 在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的 顺序和读的顺序必须一致。
2.传递 Serializable 对象(更简单,但性能较差)
java
// 让类实现 Serializable 接口
public class User implements Serializable {
// ...
}
// 传递
intent.putExtra("user_key", user);
// 接收
User receivedUser = (User) getIntent().getSerializableExtra("user_key");
两种序列化方式的比较:
- 1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
- 2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
- 3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的 持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable。
七、获取 Activity 的结果:startActivityForResult
(注意 :此方法已被标记为 deprecated
,推荐使用新的 Activity Result API,但理解其原理仍有价值)
旧方式:
java
// 启动 Activity,并期待返回结果
private static final int REQUEST_CODE_PICK_CONTACT = 1;
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(pickContactIntent, REQUEST_CODE_PICK_CONTACT);
// 在源 Activity 中重写 onActivityResult 来接收结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICK_CONTACT) {
if (resultCode == RESULT_OK) {
// 处理返回的数据 Intent 'data'
Uri contactUri = data.getData();
// ... 处理联系人 URI ...
}
}
}
新方式(Activity Result API):
-
注册一个 Activity Result Launcher。
-
启动它。
java
// 在 Activity 或 Fragment 中
private ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
// 这里是回调
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
// 处理返回的 Intent data
}
});
// 当需要启动 Activity 并获取结果时
Intent intent = new Intent(this, TargetActivity.class);
someActivityResultLauncher.launch(intent);