Abstract class as parcelable Abstract class as parcelable android android

Abstract class as parcelable


My solution is similar to evertvandenbruel's. But I identify the concrete class using an int so that I can use a switch block. I also have that switch block in a static getConcreteClass(Parcel) method.

AbstractClass.java

public abstract class AbstractClass implements Parcelable {public static final int CLASS_TYPE_ONE = 1;public static final int CLASS_TYPE_TWO = 2;public static final Creator<AbstractClass> CREATOR = new Creator<AbstractClass>() {    @Override    public AbstractClass createFromParcel(Parcel source) {        return AbstractClass.getConcreteClass(source);    }    @Override    public AbstractClass[] newArray(int size) {        return new AbstractClass[size];    }};protected String mAbstractClassString;public AbstractClass(String abstractClassString) {    mAbstractClassString = abstractClassString;}public AbstractClass(Parcel source) {    mAbstractClassString = source.readString();}public static AbstractClass getConcreteClass(Parcel source) {    switch (source.readInt()) {        case CLASS_TYPE_ONE:            return new ConcreteClassOne(source);        case CLASS_TYPE_TWO:            return new ConcreteClassTwo(source);        default:            return null;    }}@Overridepublic int describeContents() {    return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {    dest.writeString(mAbstractClassString);}@Overridepublic String toString() {    return "Parent String: " + mAbstractClassString + '\n';}}

ConcreteClassOne.java

public class ConcreteClassOne extends AbstractClass {private String mString;public ConcreteClassOne(String abstractClassMemberString, String string) {    super(abstractClassMemberString);    mString = string;}public ConcreteClassOne(Parcel source) {    super(source);    mString = source.readString();}@Overridepublic void writeToParcel(Parcel dest, int flags) {    dest.writeInt(CLASS_TYPE_ONE);    super.writeToParcel(dest, flags);    dest.writeString(mString);}@Overridepublic String toString() {    return super.toString().concat("Child String: " + mString);}}

ConcreteClassTwo.java

public class ConcreteClassTwo extends AbstractClass {private String mString;private int mInt;public ConcreteClassTwo(String abstractClassString, String string, int anInt) {    super(abstractClassString);    mString = string;    mInt = anInt;}public ConcreteClassTwo(Parcel source) {    super(source);    mString = source.readString();    mInt = source.readInt();}@Overridepublic void writeToParcel(Parcel dest, int flags) {    dest.writeInt(CLASS_TYPE_TWO);    super.writeToParcel(dest, flags);    dest.writeString(mString);    dest.writeInt(mInt);}@Overridepublic String toString() {    String string = super.toString();    for (int i = 0; i < mInt; i++) {        string = string.concat("Child String: " + mString + '\n');    }    return string;}}


The selected answer (from evertvandenbruel's post) has a bug in it. The correct code must account for parceling when just one of the subclasses is being parceled, not just a list of the superclass objects.

All the other code should be the same, the key is that you MUST read in the type variable in ALL creators (see code below). Otherwise there will be issues with the ordering when trying to unparcel a subclass object

Ex:

package com.example.parcelable_example.model;import android.os.Parcel;import android.os.Parcelable;public class Cat extends Animal{    public Cat(String name){        super(name, "Cat");    }    public int describeContents() {        return 0;    }    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(getType());        super.writeToParcel(dest, flags);    }    public Cat(Parcel source) {        super(source);          }    public static final Parcelable.Creator<Cat> CREATOR = new Parcelable.Creator<Cat>() {        public Cat createFromParcel(Parcel in) {            /** DO NOT FORGET THIS!!! **/            type = in.readString();            return new Cat(in);        }        public Cat[] newArray(int size) {            return new Cat[size];        }    };}


This question arises from a false assumption.


Here is a quote from the original post.

The abstract class ProjectItem needs a CREATOR as it should be parcelable.

In fact, It is not necessary for the super class to define CREATOR since it is abstract.


Here is a minimal example which demonstrates the method.

/*   Super class   */abstract class SuperClass        implements Parcelable {    protected SuperClass(Parcel in) {        mSuperId = in.readLong();    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeLong(mSuperId);    }}/*   Sub class   */public class SubClass        extends SuperClass {    protected SubClass(Parcel in) {        super(in);        mSubId = in.readLong();    }    @Override    public void writeToParcel(Parcel dest, int flags) {        super.writeToParcel(dest, flags);        dest.writeLong(mSubId);    }    @Override    public int describeContents() {        return 0;    }    public static final Creator<SubClass> CREATOR = new Creator<SubClass>() {        @Override        public SubClass createFromParcel(Parcel in) {            return new SubClass(in);        }        @Override        public SubClass[] newArray(int size) {            return new SubClass[size];        }    };}/*   Usage   */class AnotherClass {    void aMethod() {        Bundle args = new Bundle();        args.putParcelable("EXTRA_SUPER_CLASS", subClassObject);    }}