Android Parcelable和Serializable的区别
一、什么是序列化?为什么要序列化?怎么进行序列化?
- 序列化:将对象转化成字节流。对象序列化后,可以在进程内、网络间进行传输,也可以做本地持久化存储。
- 反序列化:将字节流转成成对象。
- 为什么要序列化:系统底层并不认识对象,数据传输是以字节序列(字节流)的形式传输,以进程间通信为例,需要将对象将转化成字节序列,然后在目标进程里通过反序列化字节序列,将字节序列转成对象。
- 序列化方式: Serializable/ Parcelable / JSON
二、序列化
- 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();
- 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;
}
}
- JSON
// 序列化
JSONObject.toJSON();
反序列化
JSONObject.parseObject()
通过上述方法可以实现对象的深拷贝 。
总结
- 作用: Serializable的作用是为了将对象保存的本地、数据库、网络,方便数据传输,这中传输可以是跨进程的。Parcelable的设计初衷是为了解决Serializable效率过慢,这些数据仅在内存中存在。parcelable 是将整个对象分解,分解后的对象都支持在intent中进行传输
- 效率及选择 Parcelable的性能比Serializable(利用反射实现序列化,会产生大量对象)好,在内存开销方面较小,所以在内存内数据传输是推荐使用parcelable,而Serializable可将数据持久化方便保存,所以需要保存或者网络传输时选择Serializable。
- 编程实现 对于Serializable,类只需要实现其接口,并提供一个序列化版本serialVersionUID即可,serialVersionUID 允许开发人员显式地管理类的版本。通过手动指定 serialVersionUID,开发人员可以确保在类的结构发生变化时,仍然能够反序列化旧版本的对象,而不会导致 InvalidClassException。 版本检查:在反序列化时,serialVersionUID 用于验证被序列化的对象是否与当前类的版本兼容。如果版本号不匹配,反序列化操作将失败,以避免数据不一致性。
- 为什么不能用Parcelable进行存储:不能保证数据的持续性;如果对象数据发生变化时,可能反序列化失败;Android不同版本Parcelable序列化方式可能不一样;这是因为磁盘上的数据可能会因为外部因素(如系统更新、设备更换等)而发生变化,而Parcelable不能很好地处理这种变化