泛型抽象基类子类列表的Parcelable序列化/反序列化问题
泛型基类
Base<T>的Parcelable实现及列表打包解包方案 一、Parcelable接口实现位置与CREATOR的放置
- 抽象基类
Base<T>需要实现Parcelable接口,用来处理所有子类通用的打包/解包逻辑(比如通用成员变量的读写)。但由于T mData的具体类型只有子类才知道,基类无法直接处理它的序列化,所以必须在基类中定义抽象方法,让子类实现mData的具体读写逻辑:protected abstract void writeDataToParcel(Parcel dest, int flags); protected abstract void readDataFromParcel(Parcel in); - 每个子类(如
Sub1、Sub2)必须实现上述抽象方法,针对自身的T类型完成mData的打包和解包。同时,CREATOR必须放在每个子类中——因为基类是抽象类无法实例化,而每个子类是具体类,需要自己的CREATOR来生成实例。
代码示例
基类Base<T>
public abstract class Base<T> implements Parcelable { protected T mData; protected String commonField; // 通用示例字段 // 普通构造方法 public Base(String commonField) { this.commonField = commonField; } // 解包专用构造方法,调用子类的readDataFromParcel protected Base(Parcel in) { this.commonField = in.readString(); readDataFromParcel(in); } // 子类需实现:写入mData到Parcel protected abstract void writeDataToParcel(Parcel dest, int flags); // 子类需实现:从Parcel读取mData protected abstract void readDataFromParcel(Parcel in); @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // 先写通用字段 dest.writeString(commonField); // 再让子类写自己的mData writeDataToParcel(dest, flags); } }
子类Sub1(T=byte[])
public class Sub1 extends Base<byte[]> { public Sub1(String commonField, byte[] data) { super(commonField); this.mData = data; } protected Sub1(Parcel in) { super(in); } @Override protected void writeDataToParcel(Parcel dest, int flags) { dest.writeByteArray(mData); } @Override protected void readDataFromParcel(Parcel in) { this.mData = in.createByteArray(); } // 子类专属的CREATOR public static final Creator<Sub1> CREATOR = new Creator<Sub1>() { @Override public Sub1 createFromParcel(Parcel in) { return new Sub1(in); } @Override public Sub1[] newArray(int size) { return new Sub1[size]; } }; }
子类Sub2(T=Object,假设Object实现Serializable)
public class Sub2 extends Base<Object> { public Sub2(String commonField, Object data) { super(commonField); this.mData = data; } protected Sub2(Parcel in) { super(in); } @Override protected void writeDataToParcel(Parcel dest, int flags) { dest.writeSerializable(mData); } @Override protected void readDataFromParcel(Parcel in) { this.mData = in.readSerializable(); } public static final Creator<Sub2> CREATOR = new Creator<Sub2>() { @Override public Sub2 createFromParcel(Parcel in) { return new Sub2(in); } @Override public Sub2[] newArray(int size) { return new Sub2[size]; } }; }
二、List<Base<T>>的整体打包与解包
由于列表中包含不同子类的实例,打包时需要先标记每个实例的类型,解包时根据类型找到对应的CREATOR来实例化对象。这里提供两种方案:
方案1:使用枚举标记类型(推荐,无反射更安全高效)
打包逻辑
// 先定义类型枚举 enum InstanceType { SUB1, SUB2 } public void writeBaseList(Parcel dest, List<Base<?>> instancesList) { // 先写入列表长度 dest.writeInt(instancesList.size()); for (Base<?> instance : instancesList) { // 写入实例类型标记 if (instance instanceof Sub1) { dest.writeInt(InstanceType.SUB1.ordinal()); } else if (instance instanceof Sub2) { dest.writeInt(InstanceType.SUB2.ordinal()); } // 写入实例本身 dest.writeParcelable(instance, 0); } }
解包逻辑
public List<Base<?>> readBaseList(Parcel in) { List<Base<?>> list = new ArrayList<>(); int size = in.readInt(); for (int i = 0; i < size; i++) { int typeOrdinal = in.readInt(); InstanceType type = InstanceType.values()[typeOrdinal]; Base<?> instance = null; switch (type) { case SUB1: instance = Sub1.CREATOR.createFromParcel(in); break; case SUB2: instance = Sub2.CREATOR.createFromParcel(in); break; } if (instance != null) { list.add(instance); } } return list; }
方案2:使用反射(无需维护枚举,适合子类较多的场景)
打包逻辑
public void writeBaseList(Parcel dest, List<Base<?>> instancesList) { dest.writeInt(instancesList.size()); for (Base<?> instance : instancesList) { // 写入实例的全类名 dest.writeString(instance.getClass().getName()); dest.writeParcelable(instance, 0); } }
解包逻辑
public List<Base<?>> readBaseList(Parcel in) { List<Base<?>> list = new ArrayList<>(); int size = in.readInt(); for (int i = 0; i < size; i++) { try { // 读取类名并反射获取Class String className = in.readString(); Class<? extends Base<?>> clazz = (Class<? extends Base<?>>) Class.forName(className); // 获取子类的CREATOR静态字段 Creator<? extends Base<?>> creator = clazz.getField("CREATOR").get(null); // 创建实例 Base<?> instance = creator.createFromParcel(in); list.add(instance); } catch (Exception e) { // 处理反射异常(类不存在、CREATOR未定义等) e.printStackTrace(); } } return list; }
内容的提问来源于stack exchange,提问作者Bak Itzik
相关产品推荐
相关产品推荐

