Android Parcelable和Serializable的区别

84 阅读3分钟

Android Parcelable和Serializable的区别

一、什么是序列化?为什么要序列化?怎么进行序列化?

  1. 序列化:将对象转化成字节流。对象序列化后,可以在进程内、网络间进行传输,也可以做本地持久化存储。
  2. 反序列化:将字节流转成成对象。
  3. 为什么要序列化:系统底层并不认识对象,数据传输是以字节序列(字节流)的形式传输,以进程间通信为例,需要将对象将转化成字节序列,然后在目标进程里通过反序列化字节序列,将字节序列转成对象。
  4. 序列化方式: Serializable/ Parcelable / JSON

二、序列化

  1. Serializable
// 序列化
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
//  反序列化
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
List<T> dest = (List<T>) in.readObject();
  1. Parcelable
public class PUtil {

    private static final String SP_NAME = "sp_parcel";
    private static final String PARCEL_KEY = "parcel_key";

    //  序列化
    public static byte[] marshall(Parcelable parcelable) {
        Parcel parcel = Parcel.obtain();
        parcel.setDataPosition(0);
        parcel.writeValue(parcelable);
        byte[] bytes = parcel.marshall();
        parcel.recycle();
        return bytes;
    }

    //将bytes经过base64转换成字符串并存储到sp中
    public static void save(Context context, byte[] bytes) {
        SharedPreferences preferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = preferences.edit();
        String saveStr = Base64.encodeToString(bytes, 0);
        editor.putString(PARCEL_KEY, saveStr);
        editor.apply();
    }

    //反序列化
    public static Object getParcel(Context context) {
        SharedPreferences preferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
        byte[] bytes = Base64.decode(preferences
                .getString(PARCEL_KEY, "").getBytes(), Base64.DEFAULT);
        //从bytes中获取Parcel
        Parcel parcel = unmarshall(bytes);
        return parcel.readValue(context.getClassLoader());
    }

    //从byte数组中获取数据,存入自身的Parcel中
    private static Parcel unmarshall(byte[] bytes) {
        Parcel parcel = Parcel.obtain();
        parcel.unmarshall(bytes, 0, bytes.length);
        parcel.setDataPosition(0);
        return parcel;
    }
}
  1. JSON
// 序列化
JSONObject.toJSON();
反序列化
JSONObject.parseObject()

通过上述方法可以实现对象的深拷贝 。

总结

  1. 作用: Serializable的作用是为了将对象保存的本地、数据库、网络,方便数据传输,这中传输可以是跨进程的。Parcelable的设计初衷是为了解决Serializable效率过慢,这些数据仅在内存中存在。parcelable 是将整个对象分解,分解后的对象都支持在intent中进行传输
  2. 效率及选择 Parcelable的性能比Serializable(利用反射实现序列化,会产生大量对象)好,在内存开销方面较小,所以在内存内数据传输是推荐使用parcelable,而Serializable可将数据持久化方便保存,所以需要保存或者网络传输时选择Serializable。
  3. 编程实现 对于Serializable,类只需要实现其接口,并提供一个序列化版本serialVersionUID即可,serialVersionUID 允许开发人员显式地管理类的版本。通过手动指定 serialVersionUID,开发人员可以确保在类的结构发生变化时,仍然能够反序列化旧版本的对象,而不会导致 InvalidClassException。 版本检查:在反序列化时,serialVersionUID 用于验证被序列化的对象是否与当前类的版本兼容。如果版本号不匹配,反序列化操作将失败,以避免数据不一致性。
  4. 为什么不能用Parcelable进行存储:不能保证数据的持续性;如果对象数据发生变化时,可能反序列化失败;Android不同版本Parcelable序列化方式可能不一样;这是因为磁盘上的数据可能会因为外部因素(如系统更新、设备更换等)而发生变化,而Parcelable不能很好地处理这种变化