Write a sub class of Parcelable to another Parcel

AndroidParcelable

Android Problem Overview


I have a class that implements Parcelable interface:

class A implements Parcelable {

}

I have another class B that contains an A object as an instance variable. In the writeToPacel inside class B, I want to write object B to the Parcel:

class B implements Parcelable{

    public void writeToParcel(Parcel dest, int flags) {
		dest.write ??? 
	}
}

How can I write and read it?

Android Solutions


Solution 1 - Android

class B implements Parcelable{
//lets assume you have A as a data member 

A obj;
public void writeToParcel(Parcel dest, int flags) {

        dest.writeParcelable(obj , flags);

    }
}

if you want to read it use this

 obj = in.readParcelable(A.class.getClassLoader());

Solution 2 - Android

A better way to handle this that avoids reflexion would be to simply call the static creator in the target type like this:

this.amazingObject = AmazingObject.CREATOR.createFromParcel(in);

and write it to the Parcelable using this.amazingObject.writeToParcel(Parcel, int)

Internally, when calling readParcelable(ClassLoader) this happens:

public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
    Parcelable.Creator<T> creator = readParcelableCreator(loader);
    if (creator == null) {
        return null;
    }
    if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
        return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
    }
    return creator.createFromParcel(this);
}

As you can see the last call of that method is just calling the right Creator but inside readParcelableCreator there is a whole lot of reflexion that we can avoid by just calling it directly.

This utility calls may be useful:

import android.os.Parcel;
import android.os.Parcelable;

public class Parcels {

	public static void writeBoolean(Parcel dest, Boolean value) {
		dest.writeByte((byte) (value != null && value ? 1 : 0));
	}

	public static Boolean readBoolean(Parcel in){
		return in.readByte() != 0;
	}

	public static void writeParcelable(Parcel dest, int flags, Parcelable parcelable) {
		writeBoolean(dest, parcelable == null);
		if (parcelable != null) {
			parcelable.writeToParcel(dest, flags);
		}
	}

	public static <T extends Parcelable> T readParcelable(Parcel in, Parcelable.Creator<T> creator) {
		boolean isNull = readBoolean(in);
		return isNull ? null : creator.createFromParcel(in);
	}

}

Solution 3 - Android

The line:

obj = (A)in.readParcelable(A.class.getClassLoader());

should change to:

obj = (A)in.readParcelable(B.class.getClassLoader());

I encountered the same problem and did several Google search, many webpage or tutorial suggests we use A.class.getClassLoader() because we are casting to A, but actually it is WRONG because you will get a null value, we must use B.class.getClassLoader() because the codes are INSIDE class B. I just did not know why but it can get the correct A object in this way.

Welcome to comment and verify!!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser4o01View Question on Stackoverflow
Solution 1 - AndroidconfuciusView Answer on Stackoverflow
Solution 2 - AndroidpabliscoView Answer on Stackoverflow
Solution 3 - AndroidAlisonView Answer on Stackoverflow