Android通过Intent传递自定义对象的两种方式
作者:雨白
前言
我们经常会使用 Intent
来启动 Activity
、发送广播等。在进行上述操作的过程中,我们还可以往 Intent
对象中添加额外的数据,比如:
// MainActivity.kt val intent = Intent(this, AnotherActivity::class.java) intent.putExtra("name", "Martin") intent.putExtra("age", 21) startActivity(intent)
以此来完成数据的传递:
// AnotherActivity.kt val name = intent.getStringExtra("name") ?: "Unknown Name" val age = intent.getIntExtra("age", -1)
但问题在于 putExtra
可传递的数据类型是有限的,如果你想传递自定义对象,就行不通了。但请别担心,我们接下来就来学习如何通过 Intent
传递自定义对象。
方式一:Serializable
Serializable
翻译过来是序列化的意思,表示将一个对象转换为可存储或可传输的状态,序列化后的对象可被存储到本地,也可在网络上进行传输。
序列化一个类,其实非常简单,只需让这个类实现 Serializable
接口即可。例如:
class Person : Serializable { var name = "" var age = 0 }
这样,所有的 Person
对象都是可序列化的了。现在,我们想要传递一个 Person
对象,只需这样:
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
对象即可。
// val person_from_intent: Person = intent.getSerializableExtra("person") as Person
不过,这个方法已经被废弃了。原因在于它不能保证类型安全,如果获取到的不是 Person
类型的对象,又或是键名拼写错误导致返回 null
,那么在运行时,as
强制类型转换可能会失败并导致程序崩溃。
所以,现在我们会使用更安全的重载方法 getSerializableExtra(String, Class<T>)
。这个方法是在 Android 13 (API 33) 引入的,为了兼容所有版本,我们需要这样写:
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
类的代码将会是这样的:
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
文件中添加插件依赖:
plugins { id("kotlin-parcelize") }
然后,修改 Person
类:
import kotlinx.parcelize.Parcelize @Parcelize data class Person(var name: String, var age: Int) : Parcelable
只需加上一个 @Parcelize
注解,就可以省去了一大堆模板代码的麻烦。
注意:使用 @Parcelize 时,所有要传递的数据都必须在类的主构造函数中声明。
接下来,在获取 Intent
中的数据时,只需使用 getParcelableExtra()
方法即可。同样地,需要处理版本兼容问题:
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") }
对比
对比 Serializable
和 Parcelable
这两种方式,Serializable
的实现非常简单,但它序列化时会用到反射,导致性能开销大。Parcelable
则通过显式的读写操作来分解对象,没有反射的开销,效率要高得多。
因此,在安卓开发中,通常情况下,我们都会选择使用 Parcelable
的方式。
以上就是Android通过Intent传递自定义对象的两种方式的详细内容,更多关于Android Intent传递自定义对象的资料请关注脚本之家其它相关文章!