Android - Serializable和Parcelable

一、简介Serializable

Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象 可以在网络上进行传输,也可以存储到本地。至于序列化的方法非常简单,只需要让一个类去 实现Serializable这个接口就可以了。

比如说有一个Person类,其中包含了name和age这两个字段,如果想要将它序列化,就可以这 样写:

class Person : Serializable {
 var name = ""
 var age = 0
}

这里我们让Person类实现了Serializable接口,这样所有的Person对象都是可序列化的 了。 然后在FirstActivity中只需要这样写:

val person = Person()
person.name = "Tom"
person.age = 20
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("person_data", person)
startActivity(intent)

可以看到,这里我们创建了一个Person的实例,并将它直接传入了Intent的putExtra()方法 中。由于Person类实现了Serializable接口,所以才可以这样写。

接下来在SecondActivity中获取这个对象也很简单,写法如下:

val person = intent.getSerializableExtra("person_data") as Person

这里调用了Intent的getSerializableExtra()方法来获取通过参数传递过来的序列化对 象,接着再将它向下转型成Person对象,这样我们就成功实现了使用Intent传递对象的功能。

需要注意的是,这种传递对象的工作原理是先将一个对象序列化成可存储或可传输的状态,传 递给另外一个Activity后再将其反序列化成一个新的对象。虽然这两个对象中存储的数据完全一 致,但是它们实际上是不同的对象,这一点希望你能了解清楚。

二、Parcelable

除了Serializable之外,使用Parcelable也可以实现相同的效果,不过不同于将对象进行序列 化,Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是 Intent所支持的数据类型,这样就能实现传递对象的功能了。

class Person : Parcelable {
 var name = ""
 var age = 0
 override fun writeToParcel(parcel: Parcel, flags: Int) {
 parcel.writeString(name) // 写出name
 parcel.writeInt(age) // 写出age
 }
 override fun describeContents(): Int {
 return 0
 }
 companion object CREATOR : Parcelable.Creator {
 override fun createFromParcel(parcel: Parcel): Person {
 val person = Person()
 person.name = parcel.readString() ?: "" // 读取name
 person.age = parcel.readInt() // 读取age
 return person
 }
 override fun newArray(size: Int): Array {
 return arrayOfNulls(size)
 }
 }
}

Parcelable的实现方式要稍微复杂一些。可以看到,首先我们让Person类实现了Parcelable 接口,这样就必须重写describeContents()和writeToParcel()这两个方法。其中 describeContents()方法直接返回0就可以了,而在writeToParcel()方法中,我们需要 调用Parcel的writeXxx()方法,将Person类中的字段一一写出。注意,字符串型数据就调用 writeString()方法,整型数据就调用writeInt()方法,以此类推。

除此之外,我们还必须在Person类中提供一个名为CREATOR的匿名类实现。这里创建了 Parcelable.Creator接口的一个实现,并将泛型指定为Person。接着需要重写 createFromParcel()和newArray()这两个方法,在createFromParcel()方法中,我们 要创建一个Person对象进行返回,并读取刚才写出的name和age字段。其中name和age都是 调用Parcel的readXxx()方法读取到的,注意这里读取的顺序一定要和刚才写出的顺序完全 相同。而newArray()方法中的实现就简单多了,只需要调用arrayOfNulls()方法,并使用 参数中传入的size作为数组大小,创建一个空的Person数组即可。

接下来,在FirstActivity中我们仍然可以使用相同的代码来传递Person对象,只不过在 SecondActivity中获取对象的时候需要稍加改动,如下所示

val person = intent.getParcelableExtra("person_data") as Person

注意,这里不再是调用getSerializableExtra()方法,而是调用 getParcelableExtra()方法来获取传递过来的对象,其他的地方完全相同。

不过,这种实现方式写起来确实比较复杂,为此Kotlin给我们提供了另外一种更加简便的用法, 但前提是要传递的所有数据都必须封装在对象的主构造函数中才行。

修改Person类中的代码,如下所示:

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

没错,就是这么简单。将name和age这两个字段移动到主构造函数中,然后给Person类添加一 个@Parcelize注解即可,是不是比之前的用法简单了好多倍?

你可能感兴趣的:(android)