场景设定
假设我们要从 MainActivity 跳转到 SecondActivity,并传递两个参数:

- 一个字符串:
"Hello from MainActivity" - 一个数字:
2025
使用 Intent 的 putExtra() (最常用)
这是最直接、最常用的方法,适用于传递少量、简单的数据类型。
发送方 (MainActivity)
使用 Intent 的 putExtra() 方法将数据附加到 Intent 对象中。
// 在 MainActivity.kt 中
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 1. 创建一个 Intent,指定从当前 Activity 到 SecondActivity
val intent = Intent(this, SecondActivity::class.java)
// 2. 使用 putExtra() 方法添加参数
// 第一个参数是 "键" (key),第二个参数是 "值" (value)
// 键是字符串,建议使用常量或包名作为前缀,以避免冲突
intent.putExtra("EXTRA_USER_MESSAGE", "Hello from MainActivity")
intent.putExtra("EXTRA_USER_ID", 2025)
// 3. 启动 SecondActivity
startActivity(intent)
}
}
接收方 (SecondActivity)
在目标 Activity 的 onCreate() 或 onNewIntent() 方法中,通过 intent 对象获取数据。
// 在 SecondActivity.kt 中
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.widget.TextView
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
// 1. 获取启动当前 Activity 的 Intent 对象
val intent = intent
// 2. 使用 get...Extra() 方法根据键来获取值
// 必须提供默认值,以防 Intent 中没有这个键
val message = intent.getStringExtra("EXTRA_USER_MESSAGE") ?: "No message received"
val id = intent.getIntExtra("EXTRA_USER_ID", -1) // -1 是默认值
// 3. 将获取到的数据显示在界面上
findViewById<TextView>(R.id.tvReceivedData).text = "Message: $message, ID: $id"
}
}
优点:

- 简单直接,易于理解和使用。
- 适用于所有基本数据类型(String, int, boolean, float, double, char, Bundle 等)。
缺点:
- 如果传递的数据很多或很复杂,代码会变得臃肿。
- 类型安全较差,如果键名写错,会在运行时(而不是编译时)导致
NullPointerException。
使用 Bundle (更规范)
Bundle 本质上是一个键值对的数据容器,Intent 内部也使用了 Bundle,将数据先放入 Bundle,再将 Bundle 放入 Intent,是一种更结构化的做法。
发送方 (MainActivity)
// 在 MainActivity.kt 中
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 1. 创建一个 Bundle 对象
val bundle = Bundle()
// 2. 向 Bundle 中添加数据
bundle.putString("EXTRA_USER_MESSAGE", "Hello from MainActivity via Bundle")
bundle.putInt("EXTRA_USER_ID", 2025)
// 3. 创建 Intent
val intent = Intent(this, SecondActivity::class.java)
// 4. 将 Bundle 放入 Intent
intent.putExtras(bundle)
// 或者一步到位: intent.putExtras(Bundle().apply { ... })
startActivity(intent)
}
}
接收方 (SecondActivity)
接收方代码和方法一完全一样,因为 Intent 会把 Bundle 里的数据“平铺”到自己身上。
// 在 SecondActivity.kt 中
// ... (代码同方法一)
val message = intent.getStringExtra("EXTRA_USER_MESSAGE") ?: "No message received"
val id = intent.getIntExtra("EXTRA_USER_ID", -1)
// ...
优点:

- 逻辑更清晰,先将所有数据打包,再统一发送。
- 方便将数据集一次性传递。
缺点:
- 对于接收方来说,和使用
putExtra没有区别,并没有提升类型安全性。
使用 Kotlin 的 by intent() 扩展属性 (推荐,现代 Android 开发最佳实践)
这是 Google 推荐的现代 Android 开发方式,利用了 Kotlin 的属性委托功能,能让你的代码更简洁、更安全。
添加依赖
确保你的项目已经添加了 androidx-activity-ktx 和 androidx-fragment-ktx 依赖,它们通常在新项目中默认包含。
// 在 app/build.gradle 中
dependencies {
implementation 'androidx.activity:activity-ktx:1.8.2'
implementation 'androidx.fragment:fragment-ktx:1.6.2'
// ... 其他依赖
}
定义接收参数的类
创建一个数据类来封装所有需要传递的参数,这是实现类型安全的关键!
// 在一个单独的文件中,UserActivityParams.kt
package com.example.myapp
data class UserActivityParams(
val message: String,
val id: Int
)
发送方 (MainActivity)
代码依然很简单,但我们需要手动创建 Bundle 并放入数据。
// 在 MainActivity.kt 中
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 1. 创建 Bundle 并放入所有参数
val params = Bundle().apply {
putString("EXTRA_USER_MESSAGE", "Hello from MainActivity with KTX")
putInt("EXTRA_USER_ID", 2025)
}
// 2. 创建 Intent 并放入 Bundle
val intent = Intent(this, SecondActivity::class.java).apply {
putExtras(params)
}
startActivity(intent)
}
}
接收方 (SecondActivity) - 核心步骤
使用 by intent() 委托来自动获取参数。
// 在 SecondActivity.kt 中
import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf // 可选,用于更方便地创建 Bundle
import com.example.myapp.UserActivityParams // 导入我们定义的数据类
class SecondActivity : AppCompatActivity() {
// 使用 by intent() 委托来自动获取参数
// 它会尝试从 Intent 中获取键为 "EXTRA_USER_MESSAGE" 的字符串和 "EXTRA_USER_ID" 的整数
// 并将它们构造成一个 UserActivityParams 对象
private val params: UserActivityParams by intent()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
// 直接使用 params 对象,它不为 null (除非你在委托中设置了可为 null)
// 如果参数缺失,默认会抛出 IllegalArgumentException,你可以处理它
try {
findViewById<TextView>(R.id.tvReceivedData).text = "Message: ${params.message}, ID: ${params.id}"
} catch (e: IllegalArgumentException) {
// 处理参数缺失的情况
findViewById<TextView>(R.id.tvReceivedData).text = "Error: Missing required parameters."
}
}
}
如何实现 by intent() 委托?
你可以自己编写一个委托函数,或者使用第三方库,这里提供一个简单的实现示例:
// 在一个工具类中,ActivityExt.kt
import android.content.Intent
import androidx.activity.ComponentActivity
// 一个简单的委托函数,用于从 Intent 中获取数据并构造成对象
fun <T> ComponentActivity.intent(key: String, creator: (Intent) -> T): Lazy<T> {
return lazy {
creator(intent)
}
}
// 然后在 SecondActivity 中这样使用 (这是更灵活的方式)
// private val params: UserActivityParams by intent { intent ->
// UserActivityParams(
// message = intent.getStringExtra("EXTRA_USER_MESSAGE") ?: "",
// id = intent.getIntExtra("EXTRA_USER_ID", -1)
// )
// }
虽然手动写委托有点麻烦,但很多项目(如 Hilt)已经提供了类似的功能,关键在于,使用数据类来定义参数,使得代码结构清晰且类型安全。
优点:
- 类型安全:编译器会检查参数是否存在,而不是在运行时才发现错误。
- 代码简洁:在接收方,
params对象可以直接使用,无需重复调用get...Extra()。 - 可读性强:数据类清晰地定义了页面需要哪些参数。
- 易于维护:增删参数只需修改数据类,影响范围小。
缺点:
- 需要额外的数据类定义。
- 对于初学者,委托的概念可能需要一点时间理解。
使用 ViewModel (适用于复杂数据和配置变更)
当页面因屏幕旋转等配置变更而销毁并重建时,Intent 中的数据会丢失,如果数据比较重要,或者需要在 Fragment 和 Activity 之间共享,使用 ViewModel 是最佳选择。
发送方 (MainActivity)
// 在 MainActivity.kt 中
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
// 获取 ViewModel
private val sharedViewModel: SharedViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 将数据设置到 ViewModel 中
sharedViewModel.userData.value = "Hello from MainActivity with ViewModel"
sharedViewModel.userId.value = 2025
// 启动 SecondActivity
startActivity(Intent(this, SecondActivity::class.java))
}
}
共享的 ViewModel
// 在 SharedViewModel.kt 中
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
// 使用 MutableLiveData 来存储可变数据
val userData = MutableLiveData<String>()
val userId = MutableLiveData<Int>()
// 如果需要对外暴露不可变的 LiveData,可以这样
// val userData: LiveData<String> = _userData
}
接收方 (SecondActivity)
// 在 SecondActivity.kt 中
import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
class SecondActivity : AppCompatActivity() {
// 获取同一个 SharedViewModel 实例
private val sharedViewModel: SharedViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
// 观察 LiveData 的变化,当数据变化时更新 UI
sharedViewModel.userData.observe(this) { message ->
sharedViewModel.userId.observe(this) { id ->
findViewById<TextView>(R.id.tvReceivedData).text = "Message: $message, ID: $id"
}
}
}
}
注意:要使用 ViewModel,需要在 AndroidManifest.xml 中为 Activity 添加 android:configChanges="orientation" 属性,或者不添加(让系统重建,ViewModel 会自动保留数据)。
优点:
- 数据持久化:完美处理屏幕旋转等配置变更,数据不会丢失。
- 组件间共享:同一个
ViewModel实例可以在Activity和其Fragment之间共享数据。
缺点:
- 对于简单的页面跳转数据传递,有点“杀鸡用牛刀”。
- 代码量相对较多。
总结与推荐
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
putExtra() |
简单、直接、通用 | 类型不安全,参数多时臃肿 | 传递少量、简单的数据,快速原型开发。 |
Bundle |
结构化,便于管理数据集 | 和 putExtra 对接收方无区别 |
需要将多个参数作为一个整体传递时。 |
Kotlin by intent() |
类型安全、代码简洁、可读性强 | 需要定义数据类,理解委托概念 | 现代 Android 开发的首选,推荐用于绝大多数场景。 |
ViewModel |
数据持久化,组件间共享 | 代码量大,略显复杂 | 需要跨配置变更保留数据,或在 Activity/Fragment 间共享数据。 |
给新手的建议:
- 从
putExtra()开始,它是最基础的知识点。 - 尽快转向
Kotlin by intent()的方式,它能让你写出更专业、更健壮的代码,这是行业内的主流做法。 - 当你遇到屏幕旋转导致数据丢失,或者需要在多个 UI 组件间共享数据时,再学习使用
ViewModel。
