Android序列化和反序列化的实现 Serializable Parcelable

版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/qq_30993595/article/details/82051204

定义

在Java中的对象序列化指的是将一个Java对象所描述的内容转换为可以存储和传输的形式的过程,通常是将对象转换为字节序列;反序列化就是相反的过程,将字节序列恢复成对象

序列化用途

  • 将对象的字节序列持久化到硬盘中,通常是存放在文件里
  • 进程间通信的时候不能直接传输对象,需将对象以字节序列的形式传输

注意

  • 类里的静态成员变量不属于对象,不会参加序列化
  • 被transient关键字修饰的成员变量不会参与序列化,因为在反序列化的过程中,transient修饰的变量的值会被设置为初始值,比如int型变量会被设置为0,引用型的会被置为null

序列化方法

在Android中实现对象序列化的方法有两种

前言:

其实有一种伪序列化/反序列化方法,就是使用DataoutputStream/DataInputStream,只不过这种方法需要开发者按顺序一个字段一个字段的进行操作,很反人类;并且不能支持复杂类型数据

    try {
            //序列化
            DataOutputStream dos = new DataOutputStream(new FileOutputStream(filePath));
            OperatorVo bean = new OperatorVo();
            bean.setAge(1);
            bean.setOpername("boy");

            dos.writeInt(bean.getAge());
            dos.writeUTF(bean.getOpername());
            dos.close();

            //反序列化
            DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
            bean.setAge(dis.readInt());
            bean.setOpername(dis.readUTF());
            dis.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
第一种:实现Serializable接口

Serializable:这是Java提供的一个为对象提供标准的序列化和反序列化的接口,是一个空的接口,没有声明任何方法,开发者只需为自己的对象实现这个接口就行了
这样就能标记这个对象,虚拟机执行序列化指令,就判定该对象可以操作,继而使用ObjectOutputStream进行序列化;反序列化亦是如此

SerialiVersionUID
通常我们实现这个接口的时候,最好指定要给SerialiVersionUID,这是序列化版本号;在进行序列化的时候,会把这个值写入序列化文件,如果没有显示的指定,那么编译器就会自动生成一个;这样在进行反序列化的时候就会检测文件中的SerialiVersionUID与这个类当前的SerialiVersionUID是否相同,如果不同就会反序列化失败,我们在类中增加或者减少字段的时候,自动生成的SerialiVersionUID也会变化,反序列化的时候也会失败;所以开发者最好显示的指定一个SerialiVersionUID

当然你不指定的话不影响序列化,但是可能会影响反序列化

示例

public class Boy implements Serializable{
    private static final long serialVersionUID = 3171346693605985494L;
    private String name;
    private String age;
    .......
}
//序列化
try {
       ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filePath));
       out.writeObject(new Boy());
       out.close();
} catch (IOException e) {
       e.printStackTrace();
}
//反序列化
try {
       ObjectInputStream in = new ObjectInputStream(new FileInputStream(filePath));
       Boyp = (Boy)in.readObject();
       in.close();
 } catch (IOException e) {
       e.printStackTrace();
 }

如果序列化对象里还引用了其它对象,那writeObject方法会进行递归序列化

第二种:实现Parcelable接口

Parcelable:是Android提供的序列化接口,通过Parcel写入和恢复数据。
Parcel:它是一个容器,他可以包含数据或者是对象引用,并且能够用于Binder的传输,同时支持序列化以及跨进程之后进行反序列化

示例

public class Boy implements Parcelable{

    private String name;
    private int age;

    public Boy() {
        super();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 返回当前对象的内容描述,如果含有文件描述符,返回1
     * 通常返回0
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 序列化功能由该方法完成,主要是通过Parcel对象的一系列write方法,将本对象的值写到Parcel对象
     * Parcel类似于使用ObjectOutputStream
     * 第二个参数有两种值,0和1
     * 1:如果当前对象需要作为返回值返回,就不能立刻释放资源
     * 通常情况下为0
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeString(name);
    }

    /**
     * 在使用AIDL进行IPC需要这个方法
     * 默认生成的模板类的对象只支持为 in 的定向 tag,因为只有writeToParcel方法
     * 如果要支持为 out 或者 inout 的定向 tag 的话,还需要实现 readFromParcel() 方法
     * 参数是一个Parcel,用它来存储与传输数据
     * 注意,此处的读值顺序应当是和writeToParcel()方法中一致的
     * @param dest
     */
    public void readFromParcel(Parcel dest){
        age = dest.readInt();
        name = dest.readString();
    }


    public Boy(Parcel parcel){
        age = parcel.readInt();
        name = parcel.readString();
    }

    /**
     * public static final 三个词一个都不能少,并且CREATOR这个名词也不能改变,必须大写
     * 
     */
    public static final Creator<Boy> CREATOR = new Creator<Boy>() {

        /**
         * 创建一个类型为T,长度为size的数组,供外部类反序列化本类数组使用
         */
        @Override
        public Boy[] newArray(int size) {
            return new Boy[size];
        }

        /**
         * 反序列化 读取顺序要与序列化顺序一致
         * 从Parcel容器中读取数据,封装成对象返回给开发者
         */
        @Override
        public Boy createFromParcel(Parcel source) {
            return new Boy(source);
        }
    };
}

对比:

  • Serializable实现简单,而Parcelable需要更多的操作
  • Serializable是Java的接口,使用时需要大量I/O操作,开销大,常用于持久化对象到本地;Parcelable效率高,使用麻烦,常用于内存级别的序列化,比如组件间的传输,网络中传输数据,IPC中数据传输等
  • Parcelable为了效率没有考虑更多的兼容性,所以数据持久化操作使用Serializable

猜你喜欢

转载自blog.csdn.net/qq_30993595/article/details/82051204