Casting objects to subclasses of a Parcelable superclass?

android, java, parcelable, serializable

Solution

I tried to reproduce your problem and I couldn't ... I used `writeParcelableArray` and NOT `writeTypedArray`. Here are the classes that I've create:

public class SuperClass implements Parcelable {
    public static final Parcelable.Creator<SuperClass> CREATOR = new Creator<SuperClass>() {

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

        @Override
        public SuperClass createFromParcel(Parcel source) {
            return new SuperClass(source);
        }
    };

    private String label;

    public SuperClass() {
    }

    protected SuperClass(Parcel source) {
        label = source.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(label);
    }

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }
}

And its child classes:

public class FirstSubClass extends SuperClass {
    public static final Parcelable.Creator<FirstSubClass> CREATOR = new Creator<FirstSubClass>() {

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

        @Override
        public FirstSubClass createFromParcel(Parcel source) {
            return new FirstSubClass(source);
        }
    };

    public FirstSubClass() {
        super();
    }

    public FirstSubClass(Parcel source) {
        super(source);
    }

}

and:

public class SecondSubClass extends SuperClass {
    public static final Parcelable.Creator<SecondSubClass> CREATOR = new Creator<SecondSubClass>() {

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

        @Override
        public SecondSubClass createFromParcel(Parcel source) {
            return new SecondSubClass(source);
        }
    };

    public SecondSubClass() {
        super();
    }

    public SecondSubClass(Parcel source) {
        super(source);
    }

}

and the `SomeClass`:

public class SomeClass implements Parcelable {
    public static final Parcelable.Creator<SomeClass> CREATOR = new Creator<SomeClass>() {

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

        @Override
        public SomeClass createFromParcel(Parcel source) {
            return new SomeClass(source);
        }
    };

    private String name;
    private SuperClass[] array;

    public SomeClass(String name, SuperClass[] array) {
        this.name = name;
        this.array = array;
    }

    protected SomeClass(Parcel source) {
        this.name = source.readString();
        Parcelable[] temp = source.readParcelableArray(SuperClass.class.getClassLoader());
        array = new SuperClass[temp.length];
        for (int i = 0; i < temp.length; i++) {
            array[i] = (SuperClass) temp[i];
        }
    }

    public String toString() {
        StringBuilder sb = new StringBuilder(name);
        if (array == null || array.length == 0) {
            sb.append(" Array is empty");
        } else {
            sb.append(" Array:");
            for (SuperClass sc : array) {
                sb.append(sc.getClass().getSimpleName());
                sb.append(",");
            }
            sb.setLength(sb.length() - 1);
        }
        return sb.toString();
    }

    public String getName() {
        return name;
    }

    public SuperClass[] getArray() {
        return array;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeParcelableArray(array, flags);
    }

    @Override
    public int describeContents() {
        return 0;
    }
}

From an activity I tap a button, create a `SomeClass` object, attach to an intent that I start a new Activity and from there I log the passed value. The function that starts the activity:

@Override
public void onClick(View v) {
    SuperClass[] array = new SuperClass[] { new SuperClass(), new FirstSubClass(), new SecondSubClass(), new SuperClass() };
    SomeClass cl = new SomeClass("My Label", array);
    Intent intent = new Intent(this, NextActivity.class);
    intent.putExtra("PASS", cl);
    startActivity(intent);
}

and from `NextActivity`:

public class NextActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //set some content if you wish
        Log.d("LOG_TAG", "Passed value: " + getIntent().getParcelableExtra("PASS"));
    }
}

I can see in the logs:

Passed value: My Label Array:SuperClass,FirstSubClass,SecondSubClass,SuperClass

Exactly what I passed from previous activity ... Check the differences from your code, I suspect you didn't write a `CREATOR` for `FirstSubClass` and `SecondSubClass`

Problem

Okay, so I have a class `SomeClass` that is `Parcelable`. It has an array of another `Parcelable` class called `SuperClass`. In my constructor for `SomeClass`, I'm trying to read the array of the `SuperClass` objects into the `myArray` instance variable. This would be straightforward; however: `SuperClass` has two subclasses `FirstSubClass` and `SecondSubClass`. The array `temp` is supposed to have a mixture of all 3, but for some reason it has only `SuperClass` objects (the `if` and `else if` statements don't seem to execute since none of the elements of `temp` are instances of the subclasses). ``` public SomeClass(Parcel in) { myArray = new SuperClass[100]; // this is probably where the problem is due to the classloader parameter: Object[] temp = in.readArray(SuperClass.class.getClassLoader()); for(int i = 0; i < myArray.length; i++) { if(temp[i] instanceof FirstSubClass) myArray[i] = (FirstSubClass) temp[i]; else if(temp[i] instanceof SecondSubClass) myArray[i] = (SecondSubClass) temp[i]; else myArray[i] = (SuperClass) temp[i]; } } ``` What I'm trying to figure out is how I can read the elements of an array of parcelable objects such that the subclasses of this object aren't automatically casted up to the superclass. (I think I may have worded my question very confusingly, please tell me if I did).

Original source