序列化接口 Serializable 和 Parcelable

Android 中序列化相关的接口有两个,这里分别对它们介绍一下

Serializable

这是 Java 提供的序列化接口,实现该接口的类就可以序列化和反序列化

Serializable 使用简单,但需要大量 I/O 操作,开销很大

serialVersionUID

如果没有显式定义 serialVersionUID,序列化也能成功,序列化运行时会根据这个类的很多方面计算出默认的 serialVersionUID

但显式定义 serialVersionUID 是确保反序列化成功的关键

为帮助我们更原滋原味地理解,摘录 Serializable 关于 serialVersionUID 的部分注释如下:

 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

 * It is also strongly advised that explicit
 * serialVersionUID declarations use the <code>private</code> modifier where
 * possible, since such declarations apply only to the immediately declaring
 * class--serialVersionUID fields are not useful as inherited members.

如果 serialVersionUID 不一样,会抛出异常 InvalidClassException,反序列化失败!

修改序列化过程

如果想修改系统默认的序列化和反序列化过程,可以重写下面的方法:

 private void writeObject(java.io.ObjectOutputStream out)
      throws IOException
      
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;
     
  private void readObjectNoData()
      throws ObjectStreamException;

Parcelable

这是 Android 提供的序列化接口,使用稍显麻烦但效率很高

只要实现这个接口,一个类的对象就能序列化并通过 IntentBinder 传递

Android 中实现该接口的类有 Intent 、Bundle、Bitmap

摘录 Parcel 类的部分注释如下:

 * Container for a message (data and object references) that can
 * be sent through an IBinder.
 
 * <p class="note">Parcel is <strong>not</strong> a general-purpose
 * serialization mechanism.  This class (and the corresponding
 * {@link Parcelable} API for placing arbitrary objects into a Parcel) is
 * designed as a high-performance IPC transport.  As such, it is not
 * appropriate to place any Parcel data in to persistent storage: changes
 * in the underlying implementation of any of the data in the Parcel can
 * render older data unreadable.</p>

可以看出,Parcelable 被设计用来进行高性能的 IPC 传输,多用于内存的序列化,不建议用在网络和持久化存储中

使用示例

一个实现 Parcelable 接口的最简单的类大致如下:

public class Sbingo666 implements Parcelable {

    private int version;
    private String name;
    private int desc;

    /**
     * 返回当前对象的内容描述
     * 如果含有文件描述符返回 1,否则返回 0
     * 几乎所有情况都返回 0
     *
     * @return 0 或 1
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 序列化
     *
     * @param dest  当前对象正要写入的 Parcel
     * @param flags 1 表示当前对象需要作为返回值返回,不能立即释放资源
     *              几乎所有情况都为 0
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.version);
        dest.writeString(this.name);
        dest.writeInt(this.desc);
    }

    protected Sbingo666(Parcel in) {
        this.version = in.readInt();
        this.name = in.readString();
        this.desc = in.readInt();
    }

    public static final Creator<Sbingo666> CREATOR = new Creator<Sbingo666>() {
        /**
         * 反序列化
         * @param source 序列化后的对象
         * @return 对象 Sbingo666
         */
        @Override
        public Sbingo666 createFromParcel(Parcel source) {
            return new Sbingo666(source);
        }

        @Override
        public Sbingo666[] newArray(int size) {
            return new Sbingo666[size];
        }
    };
}

通过代码里的注释,这个类的结构还是很好理解的

需要注意:序列化和反序列化两个方法中的字段【读写顺序】要一致!

代码生成插件

实现 Parcelable 接口需要写很多格式化的代码,确实比较麻烦

好在有插件可以帮我们完成这个工作,插件如下:
在这里插入图片描述
安装后重启AS,使用这个插件就能一键生成这些格式化的代码啦!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值