Android里的序列化:Serializable和Parcelable

Serializable

在Android开发中,Serializable是一种用于将对象序列化和反序列化的接口。它是Java的标准序列化方式,可以在任何Java平台上使用。

下面是使用Serializable进行对象序列化的步骤:

  1. 在要序列化的类中实现Serializable接口:在类定义上实现Serializable接口。
import java.io.Serializable;

public class MyObject implements Serializable {
    private int id;
    private String name;

    // 构造函数
    public MyObject(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // 省略get和set
}
  1. 序列化对象:创建一个输出流,并将对象写入该输出流。
MyObject myObject = new MyObject(1, "Example");

try {
    FileOutputStream fileOut = new FileOutputStream("path/to/file");
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    out.writeObject(myObject);
    out.close();
    fileOut.close();
} catch (IOException e) {
    e.printStackTrace();
}
  1. 反序列化对象:创建一个输入流,并从输入流中读取对象。
MyObject myObject = null;

try {
    FileInputStream fileIn = new FileInputStream("path/to/file");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    myObject = (MyObject) in.readObject();
    in.close();
    fileIn.close();
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

通过实现Serializable接口,你可以使用Java的标准序列化机制对对象进行序列化和反序列化。但需要注意的是,尽管Serializable是方便的,但它的序列化过程相对较慢,并且会消耗大量的内存。因此,在Android开发中,如果性能要求较高,建议使用Parcelable接口进行对象序列化。

原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同时才能够正常的被反序列化。serialVersionUID的详细工作机制是这样的:序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中(也可能是其他的中介),当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化,否则就说明当前类和序列化的类相比发生了某些变换

给serialVersionUID制定为1L或者采用Eclipse根据当前类结构去生成的hash值,这两者并没有本质区别。

  • 静态成员变量属于类不属于对象,所以不会参与序列化过程
  • 其次用transient关键字标记的成员变量不参与序列化过程

Parcelable接口

在Android开发中,Parcelable是一种用于将对象序列化和反序列化的接口。它比Java中的Serializable更高效,因为它是在内存中直接操作对象的字段,而不会经过IO流的序列化和反序列化过程。

下面是使用Parcelable进行对象序列化的步骤:

  1. 实现Parcelable接口:在要序列化的类中实现Parcelable接口,并实现其中的方法。Parcelable接口包括两个核心方法:writeToParcel()createFromParcel()writeToParcel()方法用于将对象的字段写入Parcel对象,createFromParcel()方法用于从Parcel对象中读取字段并创建对象。
public class MyObject implements Parcelable {
    private int id;
    private String name;

    // 构造函数
    public MyObject(int id, String name) {
        this.id = id;
        this.name = name;
    }

    protected MyObject(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<MyObject> CREATOR = new Creator<MyObject>() {
        @Override
        public MyObject createFromParcel(Parcel in) {
            return new MyObject(in);
        }

        @Override
        public MyObject[] newArray(int size) {
            return new MyObject[size];
        }
    };
}
  • 序列化对象:将对象序列化为Parcel对象。
MyObject myObject = new MyObject(1, "Example");
Parcel parcel = Parcel.obtain();
myObject.writeToParcel(parcel, 0);
  • 反序列化对象:从Parcel对象中读取字段并创建对象。
parcel.setDataPosition(0);
MyObject myObject = MyObject.CREATOR.createFromParcel(parcel);

这样,你就可以使用Parcelable接口来实现Android中的对象序列化和反序列化了。注意,要确保对象的字段顺序一致,以便正确地读取和写入Parcel对象。另外,Parcelable只适用于Android平台,如果需要在不同平台之间进行对象序列化,考虑使用其他的序列化方式,如JSON(有很便捷的api进行读入读出)

Parcelable的方法说明:

方法 功能 标记位
createFromParcel(Parcel in) 从序列化的对象中创建原始对象
newArray[int size] 创建指定长度的原始对象数组
User(Parcel in) 从序列化的对象中创建原始对象
write ToParcel(Parcel out, int flags) 将当前对象写入序列化结构中,其中flags标识有两种值0或1(参见右侧标记位)。为1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0 PARCELABLE_WRITE_RETURN_VALUE
describeContents 返回当前对象的内容描述。如果含有文件描述符,返回1(参见右侧标记位),否则返回0,几乎所有的情况都返回0 CONTENTS_FILE_DESCRIPTOR
  • 系统已经为我们提供了许多实现了Parcelable接口的类,它们都是可以直接序列化的,比如Intent、Bundle、Bitmap等,同时List和Map也可以序列化,前提是它们里面的每个元素都是可序列化的。

如何选取

Serializable是Java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化需要大量I/O操作。而Parceleble是Android中的序列化方式,因此更适合在Android平台上,缺点是麻烦,但是效率高,这是Android推荐的序列化方式,所以我们要首选Parcelable。Parcelable主要用在内存序列化上,通过Parcelable将对象序列化到存储设备中或者将对象序列化之后通过网络传输,但是过程稍显复杂,因此在这两种情况下建议大家使用Serializable。

你可能感兴趣的:(Android进阶,android)