64

I got an implementation of Parcelable working for a single class that involves no inheritance. I have problems figuring out the best way to implement the interface when it come to inheritance. Let's say I got this :

public abstract class A {
    private int a;
    protected A(int a) { this.a = a; }
}

public class B extends A {
    private int b;
    public B(int a, int b) { super(a); this.b = b; }
}

Question is, which is the recommended way to implement the Parcelable interface for B (in A? in both of them? How?)

Vincent Mimoun-Prat
  • 28,208
  • 16
  • 81
  • 124

3 Answers3

86

Here is my best solution, I would be happy to hear from somebody that had a thought about it.

public abstract class A implements Parcelable {
    private int a;

    protected A(int a) {
        this.a = a;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(a);
    }

    protected A(Parcel in) {
        a = in.readInt();
    }
}

public class B extends A {
    private int b;

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

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

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

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        super.writeToParcel(out, flags);
        out.writeInt(b);
    }

    private B(Parcel in) {
        super(in);
        b = in.readInt();
    }
}
Vincent Mimoun-Prat
  • 28,208
  • 16
  • 81
  • 124
  • 5
    Do we need to implements Parcelable in class B (child class) as well? – Cheok Yan Cheng Mar 21 '13 at 08:57
  • @jsmith no, I haven't, let me know if you try it. – Vincent Mimoun-Prat Mar 21 '13 at 10:57
  • 6
    @CheokYanCheng No, as A implements it, it means B also does (no need to repeat the `implements Parcelable` in B declaration. – Vincent Mimoun-Prat Mar 21 '13 at 10:58
  • @MarvinLabs Any reason A need not provide describeContents implementation? (I can understand why A doesn't provide CREATOR, as it is abstract and unable to create an instance of itself) Also, may I know to proper way to test whether everything is correct? Is able to save and retrieve from Bundle sufficient enough? – Cheok Yan Cheng Mar 21 '13 at 12:11
  • 1
    I have tried to pass A through AIDL and it doesn't work. B is lost. The work-around was to put the object in a Bundle and pass the bundle through AIDL. You just need to ensure that you use the correct class loader on the other side. – jsmith Mar 22 '13 at 12:16
  • This is not useful. How can we forexample really use this parcelable? When we just extend it in a single class, sure. But what if we extend it by multiple classes, like what inheritance is good for? Like how can we read this as a typed list? – Paul Woitaschek Feb 17 '15 at 16:43
  • You can't pass A. You can't even instantiate it. It's abstract? – oaskamay Oct 22 '15 at 06:15
4

This is my variant. I think it's nice because it shows the symmetry between the virtual read- and write- methods very clearly.

Side note: I think Google did a really poor job at designing the Parcelable interface.

public abstract class A implements Parcelable {
    private int a;

    protected A(int a) {
        this.a = a;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(a);
    }

    public void readFromParcel(Parcel in) {
        a = in.readInt();
    }
}

public class B extends A {
    private int b;

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

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

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

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        super.writeToParcel(out, flags);
        out.writeInt(b);
    }

    public void readFromParcel(Parcel in) {
        super(in);
        b = in.readInt();
    }
}
Dalbergia
  • 1,699
  • 1
  • 17
  • 26
osxdirk
  • 560
  • 6
  • 11
  • 1
    What happens if you want to Parcel a List of A? – Hossein Shahdoost Mar 14 '17 at 12:31
  • 2
    In `createFromParcel()`, shouldn't it be `B b = new B(in);` instead of `B b = new B(); b(in);`? The latter (your current code) won't compile, since `b(in)` isn't a valid method or constructor call. – Ted Hopp Feb 02 '18 at 21:52
1

Here is the implementation for class A in a real world setting since class B will likely have more than one object with different types other than int

It uses reflection to get the types. Then uses a sorting function to sort the fields so that reading and writing happen in the same order.

https://github.com/awadalaa/Android-Global-Parcelable

Alaa Awad
  • 3,612
  • 6
  • 25
  • 35
  • 4
    Parcelable was introduced to avoid using the Reflection API, because it's slow. What you do is combining the slow Reflection API with the modern Parcelable solution. This is not the way it's meant to be used. – andred Sep 08 '15 at 16:24