是否可以 parcel/deparcel 扩展相同基础 class 的不同对象的列表?

Is it possible to parcel/deparcel a list of different objects that extend same base class?

假设我有一个基本抽象 class(或接口),称为 "Base" 和几个扩展它的具体 class,如 Concrete1、Concrete2、Concrete3。现在,我有另一个容器 class,其中包含 "Base" 个对象的列表:

public class Container implements Parcelable {
  ...
  private List<Base> baseList;

}

假设我想将几个具体对象放入 baseList:

baseList.add(new Concrete1());
baseList.add(new Concrete2());
baseList.add(new Concrete3());
baseList.add(new Concrete2());

是否可以对baseList字段进行分块,分块后得到Concrete1、Concrete2等同类型的对象列表?怎么样?

我使用以下方法。

  1. 确保 Base 实现了 Parcelable
  2. Base中放置一个describeContents方法。
  3. Base中放入方法abstract void write2(Parcel p);方法并在每个具体class中重写它。
  4. 在每个具体class中放一个方法static Base create2(Parcel p)。这应该是 write2.
  5. 的反面
  6. Base中写一个抽象方法abstract int typeNumber()并在每个具体子class中覆盖它(每个子class应该return一个不同的值。我使用静态最终字段 CONCRETE1CONCRETE2、...我保留在 Base).

然后你可以在Base中添加以下内容:

@Override
public final void writeToParcel(Parcel p, int flags) {
    p.writeInt(typeNumber());
    write2(p);
}

public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {

    @Override
    public Base createFromParcel(Parcel p) {
        switch (p.readInt()) {
            case CONCRETE1: return Concrete1.create2(p);
            case CONCRETE2: return Concrete2.create2(p);
            // etc
            default: throw new AssertionError();
        }
    }

    @Override
    public Base[] newArray(int size) {
         return new Base[size];
    }
}

然后你可以写一个 List 使用

parcel.writeTypedList(baseList);

并使用

读回
List<Base> list = new ArrayList<Base>();
parcel.readTypedList(list, Base.CREATOR);

此方法不需要将任何 class 的名称写入 Parcel(而是写入 int 值),不需要 CREATOR 字段可以使用反射找到,并且不需要 ClassLoader.