Skip to content Skip to sidebar Skip to footer

Abstract Class As Parcelable

Basicly I have the following structure in my app: It would be straightforward to implement such a structure without the abstract class ProjectItem, but in this case I don't know h

Solution 1:

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

publicabstractclassAbstractClassimplementsParcelable {

publicstaticfinalintCLASS_TYPE_ONE=1;
publicstaticfinalintCLASS_TYPE_TWO=2;

publicstaticfinal Creator<AbstractClass> CREATOR = newCreator<AbstractClass>() {
    @Overridepublic AbstractClass createFromParcel(Parcel source) {

        return AbstractClass.getConcreteClass(source);
    }

    @Overridepublic AbstractClass[] newArray(int size) {
        returnnewAbstractClass[size];
    }
};

protected String mAbstractClassString;

publicAbstractClass(String abstractClassString) {
    mAbstractClassString = abstractClassString;
}

publicAbstractClass(Parcel source) {
    mAbstractClassString = source.readString();
}

publicstatic AbstractClass getConcreteClass(Parcel source) {

    switch (source.readInt()) {
        case CLASS_TYPE_ONE:
            returnnewConcreteClassOne(source);
        case CLASS_TYPE_TWO:
            returnnewConcreteClassTwo(source);
        default:
            returnnull;
    }
}

@OverridepublicintdescribeContents() {
    return0;
}

@OverridepublicvoidwriteToParcel(Parcel dest, int flags) {
    dest.writeString(mAbstractClassString);
}

@Overridepublic String toString() {
    return"Parent String: " + mAbstractClassString + '\n';
}
}

ConcreteClassOne.java

publicclassConcreteClassOneextendsAbstractClass {

privateString mString;

publicConcreteClassOne(String abstractClassMemberString, Stringstring) {
    super(abstractClassMemberString);

    mString = string;
}

publicConcreteClassOne(Parcel source) {
    super(source);
    mString = source.readString();
}

@OverridepublicvoidwriteToParcel(Parcel dest, int flags) {

    dest.writeInt(CLASS_TYPE_ONE);
    super.writeToParcel(dest, flags);
    dest.writeString(mString);
}

@OverridepublicStringtoString() {
    returnsuper.toString().concat("Child String: " + mString);
}
}

ConcreteClassTwo.java

publicclassConcreteClassTwoextendsAbstractClass {

privateString mString;
private int mInt;

publicConcreteClassTwo(String abstractClassString, Stringstring, int anInt) {
    super(abstractClassString);
    mString = string;
    mInt = anInt;
}

publicConcreteClassTwo(Parcel source) {
    super(source);
    mString = source.readString();
    mInt = source.readInt();
}

@OverridepublicvoidwriteToParcel(Parcel dest, int flags) {

    dest.writeInt(CLASS_TYPE_TWO);
    super.writeToParcel(dest, flags);
    dest.writeString(mString);
    dest.writeInt(mInt);
}

@OverridepublicStringtoString() {

    Stringstring = super.toString();
    for (int i = 0; i < mInt; i++) {
        string = string.concat("Child String: " + mString + '\n');
    }
    returnstring;
}
}

Solution 2:

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;

publicclassCatextendsAnimal{

    publicCat(String name){
        super(name, "Cat");
    }

    publicintdescribeContents() {
        return0;
    }

    publicvoidwriteToParcel(Parcel dest, int flags) {
        dest.writeString(getType());
        super.writeToParcel(dest, flags);
    }

    publicCat(Parcel source) {
        super(source);      
    }

    publicstaticfinal Parcelable.Creator<Cat> CREATOR = newParcelable.Creator<Cat>() {
        public Cat createFromParcel(Parcel in) {
            /** DO NOT FORGET THIS!!! **/
            type = in.readString();
            returnnewCat(in);
        }

        public Cat[] newArray(int size) {
            returnnewCat[size];
        }
    };

}

Solution 3:

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   */abstractclassSuperClassimplementsParcelable {

    protectedSuperClass(Parcel in) {
        mSuperId = in.readLong();
    }

    @OverridepublicvoidwriteToParcel(Parcel dest, int flags) {
        dest.writeLong(mSuperId);
    }

}



/*   Sub class   */publicclassSubClassextendsSuperClass {

    protectedSubClass(Parcel in) {
        super(in);
        mSubId = in.readLong();
    }

    @OverridepublicvoidwriteToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeLong(mSubId);
    }

    @OverridepublicintdescribeContents() {
        return0;
    }

    publicstaticfinal Creator<SubClass> CREATOR = newCreator<SubClass>() {

        @Overridepublic SubClass createFromParcel(Parcel in) {
            returnnewSubClass(in);
        }

        @Overridepublic SubClass[] newArray(int size) {
            returnnewSubClass[size];
        }

    };

}



/*   Usage   */classAnotherClass {

    voidaMethod() {
        Bundleargs=newBundle();
        args.putParcelable("EXTRA_SUPER_CLASS", subClassObject);
    }

}

Solution 4:

publicabstractclassAimplementsParcelable {
    privateint a;

    protectedA(int a) {
        this.a = a;
    }

    publicvoidwriteToParcel(Parcel out, int flags) {
        out.writeInt(a);
    }

    protectedA(Parcel in) {
        a = in.readInt();
    }
}

publicclassBextendsA {
    privateint b;

    publicB(int a, int b) {
        super(a);
        this.b = b;
    }

    publicstatic final Parcelable.Creator<B> CREATOR = new Parcelable.Creator<B>() {
        public B createFromParcel(Parcel in) {
            returnnew B(in);
        }

        public B[] newArray(int size) {
            returnnew B[size];
        }
    };

    publicintdescribeContents() {
        return0;
    }
}

Post a Comment for "Abstract Class As Parcelable"