Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write a sub class of Parcelable to another Parcel

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?

like image 422
user4o01 Avatar asked Sep 02 '12 20:09

user4o01


People also ask

What is Parcelable class in Java?

We need some Context! Creating a Parcelable class is a vital skill for Android Developers because it allows you to pass an object from one Activity to another. This series will walk you through step by step in the process of implementing a parcelable class and using it in a simple App. Let's get started!

What is Parcelable Android example?

Parcelable is a serialization mechanism provided by Android to pass complex data from one activity to another activity.In order to write an object to a Parcel, that object should implement the interface “Parcelable“.

How do I make a data class Parcelable?

There are 3 ways you can make your class Parcelable: Implementing the Parcelable interface and defining the serialization yourself (The traditional way) Using Android Studio plugins, like Android Parcelable code generator. Using annotation-based libraries, like Parceler.

How do you add a Parcelable implementation?

You can install this plugin by going to Android Studio -> File -> Settings -> Plugins -> Browse repositories : Here are all the Java types it supports: Types implementing Parcelable. Custom support (avoids Serializable / Parcelable implementation) for: Date , Bundle.


3 Answers

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());
like image 69
confucius Avatar answered Oct 06 '22 10:10

confucius


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);
    }

}
like image 30
pablisco Avatar answered Oct 06 '22 08:10

pablisco


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!!

like image 2
Alison Avatar answered Oct 06 '22 09:10

Alison