Say I have a base abstract class(or an interface), called "Base" and several concrete classes that extend it, like Concrete1, Concrete2, Concrete3. Now, I have another Container class that contains a list of "Base" objects:
public class Container implements Parcelable {
...
private List<Base> baseList;
}
Let's say I want to put several concrete objects into baseList:
baseList.add(new Concrete1());
baseList.add(new Concrete2());
baseList.add(new Concrete3());
baseList.add(new Concrete2());
Is it possible to implement parceling for baseList field and have a list of objects of the same types Concrete1, Concrete2, etc. after deparceling? How?
I use the following approach.
Base
implements Parcelable
.describeContents
method in Base
.abstract void write2(Parcel p);
method in Base
and override it in each concrete class.static Base create2(Parcel p)
in each concrete class. This should be the reverse of write2
.abstract int typeNumber()
in Base
and override it in each concrete subclass (each subclass should return a different value. I use static final fields CONCRETE1
, CONCRETE2
, ... that I keep in Base
).Then you can add the following to 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];
}
}
Then you can write a List
using
parcel.writeTypedList(baseList);
and read it back using
List<Base> list = new ArrayList<Base>();
parcel.readTypedList(list, Base.CREATOR);
This approach does not require the names of any classes to be written to the Parcel
(it writes int
values instead), does not require the CREATOR
fields to be found using reflection, and does not require a ClassLoader
.