使用Intent传递自定义对象的两种实现方式对比:Serializable vs Parcelable

前记

Intent 翻译过来是“意图”、“目的“的意思,就像中国旧社会的媒婆,往返于男女双方,传达信息。在程序中我们可以借助 Intent 启动活动、发送广播、启动服务等,除此之外,我们还可以在 Intent 中添加一些附加数据以达到传值的效果。Intent 实例有很多方法,比如putExtra()方法,常见的数据类型它都支持。但是当我们想去传递一些自定义对象的时候这些方法就无能为力了。这里我们介绍两种使用 Intent 传递对象的实现方式,分别是 Serializable 方式和 Parcelable 方式。

Serializable 接口

Serializable 是 Java 提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化的操作。Serializable 是序列化的意思,表示将一个对象转换成可存储或可传输的状态序列化后的对象可以在网络上进行传输,也可以存储到本地。序列化的方法很简单,只需让一个类实现 Serializable 接口就可以了,获取对象时调用getSerializableExtra()方法就可以得到通过参数传递过来的序列化对象。注意,实现 Serializable 接口的同时我们还可以声明一个 serialVersionUID,它是用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。

Parcelable 接口

Parcelable 方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是 Intent 所支持的数据类型,这样也就实现传递对象的功能了。获取对象时调用getParcelableExtra()方法就可以了。在序列化过程中需要实现的功能有序列化反序列化内容描述。序列化功能由writeToParcel方法来完成,最终是通过 Parcel 中的一系列 write 方法来完成的;反序列化功能由 CREATOR 来完成,其内部标明了如何创建序列化对象和数组,并通过 Parcel 的一系列 read 方法来完成反序列化过程;内容描述功能由 describeContents方法完成,几乎在所有情况下这个方法都应该返回0,仅当当前对象中存在文件描述符时,此方法返回1。

后记

Serializable 的优点是简单易用,它是一种标识接口,这意味着无需实现方法,Java 便会对这个对象进行高效的序列化操作;缺点是使用了反射,序列化和反序列化过程需要大量I/O操作,序列化的过程较慢。这种机制会在序列化的时候创建许多的临时对象,容易触发垃圾回收且比较耗资源。

Parcelable 的优点是效率高,速度之上,是 Android 中的序列化方式,更适合用在 Android 平台上。根据 Google 工程师的说法,实现 Parcelable 接口的类中的代码会执行的特别快。原因之一就是我们已经清楚地知道了序列化的过程,而不需要使用反射来推断。同时为了更快地进行序列化,对象的代码也需要高度优化。因此,很明显实现 Parcelable 并不容易,需要写大量的模板代码,这使得代码变得难以阅读和维护。不过,正所谓「懒就是生产力」,有人已开发Parcelable 插件,可以大大提高开发效率。