
在 Android 中传递一些数据时,我们需要将数据序列化。序列化经常会用到 Serializable 和 Parcelable 这两个类,那么你有没有想过他们的区别是什么呢?这篇文章来分析一下各自的特点及优缺点,并对比一下两种结构的区别。
在讲它们之前,先提一个问题:为什么要序列化?
为什么要序列化
Android 开发的时候,我们时长遇到传递对象的需求,但是我们无法将对象的引用传给 Activity 或者 Fragment,我们需要将这些对象放到一个 Intent 或者 Bundle 里面,然后再传递,这时候就用到了序列化。所谓序列化就是 把 Java 对象转换为字节序列的过程 ,该字节序列可以被存储到一个储存媒介里或者在网络上进行传输;反序列化就是把 字节序列恢复为 Java 对象的过程。但是我们要知道序列化与反序列化仅处理 Java 变量而不处理方法,仅对数据进行处理。
序列化的两种方式
Android 中序列化有两种方式:Serializable 以及 Parcelable。其中 Serializable 是 Java 自带的,而 Parcelable 是 Android 专有的。
Serializable
Serializable 是 Java 提供的序列化技术。使用起来非常简单,只需要让某个 Class 实现 Serializable 就可以。在 Serializable 的文档中提出,Serializable 在序列化运行时会关联一个版本号,用 serialVersionUID
来标识,主要用来验证发送者和接收者处理的是不是同一个版本的类。如果版本不一致,则会抛出 InvalidClassException
异常。要使用这个标识,需要在类里声明如下:
|
虽然不提供这个值也行,Java 会自己生成一个该值,但是最好还是能提供一个。因为受编译器版本不同、内核版本不同等等的影响,有可能同一个类计算出来的 serialVersionUID
值不同,就会导致序列化 / 反序列化失败。
当父类实现了序列化,其子类也会自动实现序列化,不需要再显式实现 Serializable 接口了。
Seralizable 无法序列化静态变量,使用 transient 修饰的对象也无法序列化。所以,当类中有静态变量时,序列化并不会保存该变量。
transient 关键字
transient 关键字的作用是 控制变量的序列化 ,在变量声明前加上该关键字,可以 阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
实现 Serializable 时,还可以添加 writeObject()
和readObject()
方法,虚拟机在序列化和反序列化时,会试图调用这两个方法,通过这两个方法,我们可以 控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。举例如下:
|
Parcelable
Parcelable 是 Android 提供的序列化方案。它的出现是为了解决 Serializable 在序列化的过程中消耗资源严重的问题,但是因为本身使用需要手动处理序列化和反序列化过程,会与具体的代码绑定,使用较为繁琐,一般只获取内存数据的时候使用。
而 Parcelable 依赖于 Parcel,Parcel 的意思是包装,实现原理是在内存中 建立一块共享数据块,序列化和反序列化均是操作这一块的数据,如此来实现。如图所示:
听起来跟 Linux 的共享内存有没有很像?对,Parcelable 可以用于 Android 的进程间通信。举个简单的例子,应用的 Activity 要与 Service 通信的话,就可以使用 Parcelable。
使用 Parcelable 要稍微麻烦一些。它需要实现以下几点:
- 类本身要实现 Parcelable 接口
- 有一个非空的静态成员变量叫
CREATOR
,并且它要实现Parcelable.Creator
接口- 覆写
createFromParcel(Parcel in)
方法 - 覆写
newArray(int size)
方法
- 覆写
- 覆写
describeContents()
方法 - 覆写
writeToParcel(Parcel dest, int flags)
方法
看起来真的好麻烦。我们还是用代码来解释一下吧:
|
两种序列化方式的对比
- Serializable 代码量少,Parcelable 代码量多。
- 在内存间传递数据的时候,Parcelable 比 Serializable 性能高、内存开销方面较小,所以推荐使用 Parcelable;而在需要保存数据到本地或者进行网络传输时,使用 Serializable。
- Serializable 在序列化时使用的是 反射 的技术,会产生大量的临时变量,从而引起频繁的 GC。而 Parcelable 方式的实现原理是将一个完整的对象进行 字节化 ,而 字节化 之后的每一部分都是 Intent 所支持的数据类型,这样也就实现传递对象的功能了。