Activity间如何高效传递参数?

99ANYc3cd6
预计阅读时长 31 分钟
位置: 首页 参数 正文

核心方法:Intent

Intent 是 Android 中不同组件(如 Activity, Service, BroadcastReceiver)之间进行通信的“信使”,在启动 Activity 时,我们通过 Intent 来携带数据。

activity之间传递参数
(图片来源网络,侵删)

Intent 有两种主要用法:

  1. 显式 Intent:明确指定要启动的组件(类名),通常用于应用内部跳转。
  2. 隐式 Intent:只指定要执行的操作(如查看地图、拨打电话),而不指定具体组件,通常用于调用系统或其他应用的功能。

传递参数主要使用显式 Intent


传递基本数据类型

这是最简单、最常用的方式,适用于 String, int, boolean, double, float, char, long, byte 等基本数据类型及其包装类。

从第一个 Activity (MainActivity) 发送数据

// MainActivity.kt
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val btnSendData = findViewById<Button>(R.id.btn_send_data)
        btnSendData.setOnClickListener {
            // 1. 创建一个 Intent
            val intent = Intent(this, SecondActivity::class.java)
            // 2. 使用 putExtra() 方法添加数据
            // 第一个参数是 "键" (Key),用于在接收方识别数据
            // 第二个参数是 "值" (Value),要传递的数据
            intent.putExtra("user_name", "张三")
            intent.putExtra("user_age", 25)
            intent.putExtra("is_logged_in", true)
            // 3. 启动 SecondActivity
            startActivity(intent)
        }
    }
}

在第二个 Activity (SecondActivity) 接收数据

// SecondActivity.kt
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        val tvReceivedData = findViewById<TextView>(R.id.tv_received_data)
        // 1. 从 getIntent() 获取启动当前 Activity 的 Intent 对象
        val intent = intent
        // 2. 使用 getXXXExtra() 方法,根据之前设置的 "键" 来获取 "值"
        // 注意:必须提供与 putExtra 时相同的键
        // 为了防止 Intent 为 null 或键不存在,可以提供默认值
        val userName = intent.getStringExtra("user_name") ?: "未知用户"
        val userAge = intent.getIntExtra("user_age", 0) // 默认值 0
        val isLoggedIn = intent.getBooleanExtra("is_logged_in", false) // 默认值 false
        // 3. 将数据显示在界面上
        val displayText = "欢迎, $userName!\n你的年龄是: $userAge\n登录状态: $isLoggedIn"
        tvReceivedData.text = displayText
    }
}

传递复杂数据类型(如对象)

当你需要传递一个自定义的对象时,不能直接使用 putExtra,Android 提供了两种主要方法来实现:ParcelableSerializable

activity之间传递参数
(图片来源网络,侵删)

使用 Parcelable (推荐)

Parcelable 的性能比 Serializable 更好,因为它通过将对象数据写入一个 Parcel 对象来实现序列化,这个过程比 Serializable 的基于 I/O 的序列化要快。

步骤:

  1. 让你的数据类实现 Parcelable 接口
  2. 实现 describeContents()writeToParcel() 方法
  3. 创建一个 Parcelable.Creator 静态成员,用于反序列化。

示例数据类 User.kt

import android.os.Parcel
import android.os.Parcelable
// 实现 Parcelable 接口
data class User(val name: String, val age: Int) : Parcelable {
    // 描述内容接口,几乎所有情况都返回 0
    override fun describeContents(): Int {
        return 0
    }
    // 将对象数据写入 Parcel
    override fun writeToParcel(dest: Parcel, flags: Int) {
        dest.writeString(name)
        dest.writeInt(age)
    }
    // CREATOR 是必须的,用于从 Parcel 中重建对象
    // 使用了 Kotlin 的 `object` 关键字创建一个单例
    companion object CREATOR : Parcelable.Creator<User> {
        // 从 Parcel 创建对象数组
        override fun createFromParcel(source: Parcel): User {
            return User(source.readString()!!, source.readInt())
        }
        // 创建一个指定大小的对象数组
        override fun newArray(size: Int): Array<User?> {
            return arrayOfNulls(size)
        }
    }
}

发送和接收

// 在 MainActivity.kt 中发送
val user = User("李四", 30)
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("user_object", user) // 直接 putExtra 即可
startActivity(intent)
// 在 SecondActivity.kt 中接收
val receivedUser = intent.getParcelableExtra<User>("user_object")
if (receivedUser != null) {
    // 使用 receivedUser.name 和 receivedUser.age
    Log.d("SecondActivity", "Received User: ${receivedUser.name}, ${receivedUser.age}")
}

Kotlin 便利方案:@Parcelize

为了手动实现 Parcelable 的繁琐代码,Kotlin Android Extensions 提供了一个注解 @Parcelize,可以让你用一行代码搞定所有事情。

import android.os.Parcelize
import kotlinx.parcelize.Parcelize
// 只需添加 @Parcelize 注解
@Parcelize
data class User(val name: String, val age: Int) : Parcelable
// 之后的使用方式完全不变,代码会自动生成

使用 Serializable

Serializable 是 Java 提供的序列化接口,非常简单,只需要让你的类实现 Serializable 接口即可,无需编写额外代码,但性能较差,不推荐在性能敏感的场景下使用。

示例数据类 User.kt

import java.io.Serializable;
// 只需实现 Serializable 接口
public class User implements Serializable {
    private String name;
    private int age;
    // 构造函数、Getter 和 Setter
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() { return name; }
    public int getAge() { return age; }
}

在 Kotlin 中:

// 只需实现 Serializable 接口
data class User(val name: String, val age: Int) : Serializable

发送和接收

发送和接收的方式与 Parcelable 完全一样,只是类实现接口不同。

// 发送
val user = User("王五", 40)
intent.putExtra("user_object", user)
// 接收
val receivedUser = intent.getSerializableExtra("user_object") as User?

使用 Bundle

Bundle 是一个键值对的数据容器,本质上 Intent 内部也使用 Bundle 来存储数据,你可以先把所有数据放进一个 Bundle,再把整个 Bundle 放进 Intent

这在需要传递大量数据或者想把数据打包管理时很有用。

// 发送方
val intent = Intent(this, SecondActivity::class.java)
val bundle = Bundle()
bundle.putString("title", "我的标题")
bundle.putInt("code", 200)
intent.putExtra("my_data_bundle", bundle)
startActivity(intent)
// 接收方
val bundle = intent.getBundleExtra("my_data_bundle")
if (bundle != null) {
    val title = bundle.getString("title")
    val code = bundle.getInt("code")
    // ...
}

使用 Activity 的 ViewModel

如果你需要在同一个屏幕内的多个 Fragment 之间,或者 Activity 和其 Fragment 之间共享数据,ViewModel 是最佳选择,它也可以用于 Activity 间传递数据,但通常不推荐用于完全独立的 Activity 间跳转,因为 ViewModel 的生命周期与 Activity 的实例绑定。

适用场景:当两个 Activity 有紧密关系,比如一个 Activity 是另一个的配置界面,返回后需要刷新数据。

优点

  • 数据在屏幕旋转等配置更改后不会丢失。
  • 自动管理生命周期,内存泄漏风险低。

简单示例

// 1. 创建一个共享的 ViewModel
// 在第一个 Activity 中
val sharedViewModel: SharedViewModel by viewModels()
sharedViewModel.setData("这是从 MainActivity 传递的数据")
// 跳转到第二个 Activity
startActivity(Intent(this, SecondActivity::class.java))
// 2. 在第二个 Activity 中获取
val sharedViewModel: SharedViewModel by viewModels()
val data = sharedViewModel.getData()
// 使用 data...

ViewModel 的具体实现和生命周期管理是另一个大话题,但它是现代 Android 开发中数据共享的核心组件。


使用 Application

你可以将数据存储在自定义的 Application 类的单例实例中,这样,任何 Activity 或 Service 都可以访问到这些数据。

适用场景:全局共享数据,比如用户登录信息、应用主题设置等。

步骤:

  1. 创建一个继承自 Application 的类
  2. AndroidManifest.xml 中声明这个类
  3. 通过 context.applicationContext 获取实例并读写数据

示例 MyApplication.kt

import android.app.Application
class MyApplication : Application() {
    // 使用 lateinit 延迟初始化
    lateinit var currentUser: User
    override fun onCreate() {
        super.onCreate()
        // 初始化数据
        currentUser = User("默认用户", 0)
    }
}

AndroidManifest.xml 中注册

<application
    android:name=".MyApplication"  <!-- 指定你的 Application 类 -->
    ...>
    ...
</application>

在 Activity 中使用

// 在任何 Activity 中
val myApp = application as MyApplication
myApp.currentUser = User("全局用户", 99)
val name = myApp.currentUser.name

注意Application 是一个全局单例,要小心使用,避免存储过多数据或导致内存泄漏。


总结与最佳实践

方法 适用场景 优点 缺点
基本数据类型 传递少量简单数据(如 ID, 标题, 状态) 简单、直接、高效 无法传递复杂对象
Parcelable 传递自定义对象(推荐) 性能高,是 Android 的标准做法 实现稍显繁琐(但 @Parcelize 解决了)
Serializable 传递自定义对象 实现极其简单,只需实现接口 性能差,基于反射,开销大
Bundle 管理和传递大量或分组的数据 数据结构化,方便管理 本质是 Intent 内部的实现,多了一层封装
ViewModel 同个任务(Task)内的 Activity/Fragment 通信 生命周期感知,数据不随配置改变丢失 不适合完全独立的 Activity 间跳转
Application 全局共享数据 任何地方都可访问,生命周期与应用相同 容易被滥用,导致内存问题,破坏组件化

最佳实践建议:

  1. 优先使用 putExtra 传递基本数据类型:这是最直接、最高效的方式。
  2. 传递对象时,首选 Parcelable + @Parcelize:这是 Android 官方推荐的性能最优方案。
  3. 只在组件间有紧密生命周期关联时使用 ViewModel:Activity 和其内部的多个 Fragment。
  4. 谨慎使用 Application:仅用于存储真正的全局状态,避免用它来临时传递数据,以免造成代码耦合和内存问题。
  5. 避免使用 Serializable 传递大对象或频繁传递的数据:除非你追求代码的极致简洁,并且不关心性能损失。
-- 展开阅读全文 --
头像
GTX 950参数有哪些核心性能指标?
« 上一篇 今天
2025新款智能手机有何突破与升级?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]