通过Intent传递自定义对象的两种方式

前言

我们经常会使用 Intent 来启动 Activity、发送广播等。在进行上述操作的过程中,我们还可以往 Intent 对象中添加额外的数据,比如:

kotlin 复制代码
// MainActivity.kt
val intent = Intent(this, AnotherActivity::class.java)
intent.putExtra("name", "Martin")
intent.putExtra("age", 21)
startActivity(intent)

以此来完成数据的传递:

kotlin 复制代码
// AnotherActivity.kt
val name = intent.getStringExtra("name") ?: "Unknown Name"
val age = intent.getIntExtra("age", -1)

但问题在于 putExtra 可传递的数据类型是有限的,如果你想传递自定义对象,就行不通 了。但请别担心,我们接下来就来学习如何通过 Intent 传递自定义对象。

方式一:Serializable

Serializable 翻译过来是序列化的意思,表示将一个对象转换为可存储或可传输的状态,序列化后的对象可被存储到本地,也可在网络上进行传输。

序列化一个类,其实非常简单,只需让这个类实现 Serializable 接口即可。例如:

kotlin 复制代码
class Person : Serializable {
    var name = ""
    var age = 0
}

这样,所有的 Person 对象都是可序列化的了。现在,我们想要传递一个 Person 对象,只需这样:

kotlin 复制代码
val person = Person()
person.name = "Jack"
person.age = 21
val intent = Intent(this, AnotherActivity::class.java)
intent.putExtra("person", person)
startActivity(intent)

那么,该怎么从 Intent 中取出这个 Person 对象呢?

答案是使用 getSerializableExtra() 方法获取序列化对象,再向下转型为 Person 对象即可。

kotlin 复制代码
// val person_from_intent: Person = intent.getSerializableExtra("person") as Person

不过,这个方法已经被废弃了。原因在于它不能保证类型安全 ,如果获取到的不是 Person 类型的对象,又或是键名拼写错误导致返回 null,那么在运行时,as 强制类型转换可能会失败并导致程序崩溃。

所以,现在我们会使用更安全 的重载方法 getSerializableExtra(String, Class<T>)。这个方法是在 Android 13 (API 33) 引入的,为了兼容所有版本,我们需要这样写:

kotlin 复制代码
val person: Person? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    intent.getSerializableExtra("person", Person::class.java)
} else {
    // 使用 as? 安全转型来避免崩溃
    @Suppress("DEPRECATION")
    intent.getSerializableExtra("person") as? Person
}

这样,我们就成功实现了通过 Intent 来传递自定义对象。

最后注意一点:在这个过程中,会将对象序列化为可存储或可传输的状态,再将其反序列化为一个新的对象。虽然这两个对象存储的数据一致,但其实是两个不相同的对象。

方式二:Parcelable

我们也可以通过 Parcelable 来完成。只不过它的实现原理是将完整的对象进行分解,使得分解后的每一个部分都是 Intent 所支持的数据类型,这样也能实现通过 Intent 来传递自定义对象的功能。

如果使用 Parcelable 的实现方式,Person 类的代码将会是这样的:

kotlin 复制代码
class Person(var name: String?, var age: Int) : Parcelable {

    constructor(parcel: Parcel) : this(
        parcel.readString(),
        parcel.readInt()
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        // 将当前类中的字段写出
        parcel.writeString(name)
        parcel.writeInt(age)
    }

    override fun describeContents(): Int {
        return 0
    }
    
    // 注意:读取字段的顺序需要和写出字段的顺序保持一致。
    companion object CREATOR : Parcelable.Creator<Person> {
        override fun createFromParcel(parcel: Parcel): Person {
            return Person(parcel)
        }

        override fun newArray(size: Int): Array<Person?> {
            return arrayOfNulls(size)
        }
    }
}

可以看到,手动编写这些模版代码非常繁琐。为此,Kotlin 提供了一种更加简便的用法。

我们先在 app/build.gradle.kts 文件中添加插件依赖:

kotlin 复制代码
plugins { 
    id("kotlin-parcelize")
}

然后,修改 Person 类:

kotlin 复制代码
import kotlinx.parcelize.Parcelize

@Parcelize
data class Person(var name: String, var age: Int) : Parcelable

只需加上一个 @Parcelize 注解,就可以省去了一大堆模板代码的麻烦。

注意:使用 @Parcelize 时,所有要传递的数据都必须在类的主构造函数中声明。

接下来,在获取 Intent 中的数据时,只需使用 getParcelableExtra() 方法即可。同样地,需要处理版本兼容问题:

kotlin 复制代码
val person: Person? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    intent.getParcelableExtra("person", Person::class.java)
} else {
    @Suppress("DEPRECATION")
    intent.getParcelableExtra<Person>("person")
}

对比

对比 SerializableParcelable 这两种方式,Serializable 的实现非常简单,但它序列化时会用到反射 ,导致性能开销大。Parcelable 则通过显式的读写操作来分解对象,没有反射的开销,效率要高得多。

因此,在安卓开发中,通常情况下,我们都会选择使用 Parcelable 的方式。

相关推荐
没有了遇见7 小时前
Android 原生定位(替代高德 / 百度等三方定位)<终极版本>
android
2501_916008898 小时前
iOS 抓包工具有哪些?全面盘点主流工具与功能对比分析
android·ios·小程序·https·uni-app·iphone·webview
2501_915921438 小时前
iOS混淆工具实战 视频流媒体类 App 的版权与播放安全保护
android·ios·小程序·https·uni-app·iphone·webview
CYRUS_STUDIO9 小时前
LLVM 全面解析:NDK 为什么离不开它?如何亲手编译调试 clang
android·编译器·llvm
CYRUS_STUDIO9 小时前
静态分析神器 + 动态调试利器:IDA Pro × Frida 混合调试实战
android·逆向
g_i_a_o_giao11 小时前
Android8 binder源码学习分析笔记(一)
android·java·笔记·学习·binder·安卓源码分析
翻滚丷大头鱼11 小时前
android 四大组件—BroadcastReceiver
android
人生游戏牛马NPC1号12 小时前
学习 Android (二十) 学习 OpenCV (五)
android·opencv·学习
2501_9160088912 小时前
uni-app iOS 日志与崩溃分析全流程 多工具协作的实战指南
android·ios·小程序·https·uni-app·iphone·webview
文 丰12 小时前
【AndroidStudio】官网下载免安装版,AndroidStudio压缩版的配置和使用
android