How to marshall and unmarshall a Parcelable to a byte array with help of Parcel?
Asked Answered
H

2

48

I want to marshall and unmarshall a Class that implements Parcelable to/from a byte array. I am well aware of the fact that the Parcelable representation is not stable and therefore not meant for long term storage of instances. But I have a use case where I need to serialize a object and it's not a showstopper if the unmarshalling fails because of an internal Android change. Also the class is already implementing the Parcelable interface.

Given an class MyClass implements Parcelable, how can I (ab)use the Parcelable interface for marshalling/unmarshalling?

Horsey answered 1/8, 2013 at 16:54 Comment(0)
H
135

First create a helper class ParcelableUtil.java:

public class ParcelableUtil {    
    public static byte[] marshall(Parcelable parceable) {
        Parcel parcel = Parcel.obtain();
        parceable.writeToParcel(parcel, 0);
        byte[] bytes = parcel.marshall();
        parcel.recycle();
        return bytes;
    }

    public static Parcel unmarshall(byte[] bytes) {
        Parcel parcel = Parcel.obtain();
        parcel.unmarshall(bytes, 0, bytes.length);
        parcel.setDataPosition(0); // This is extremely important!
        return parcel;
    }

    public static <T> T unmarshall(byte[] bytes, Parcelable.Creator<T> creator) {
        Parcel parcel = unmarshall(bytes);
        T result = creator.createFromParcel(parcel);
        parcel.recycle();
        return result;
    }
}

With the help of the util class above, you can marshall/unmarshall instances of your class MyClass implements Parcelable like so:

Unmarshalling (with CREATOR)

byte[] bytes = …
MyClass myclass = ParcelableUtil.unmarshall(bytes, MyClass.CREATOR);

Unmarshalling (without CREATOR)

byte[] bytes = …
Parcel parcel = ParcelableUtil.unmarshall(bytes);
MyClass myclass = new MyClass(parcel); // Or MyClass.CREATOR.createFromParcel(parcel).

Marshalling

MyClass myclass = …
byte[] bytes = ParcelableUtil.marshall(myclass);
Horsey answered 1/8, 2013 at 16:54 Comment(6)
parcel.setDataPosition(0); // this is extremely important! this help me much. the missing of Android document of this, is really suck.Wiliness
Thank you very much for this tip. Implementing Parcelable (which is hugely error-prone and you will get meaningless runtime exceptions and angry customers if not done right) is such a PITA - I'm avoiding Parcelables in my code altogether and I'm using Serializables. On modern phones, the speed hit is hardly noticeable.Deering
The only problem with this approach, however, is that unmarshalling a subclass of class that implements Parcelable will not be as straightforward. You'll need to pass along extra info from which you can judge the correct Creator to use.Naturalist
Flow, How use your util class for ParcelableArrayList case ? Thank you very much!Kei
@Horsey where to do Marshalling and UnMarshalling in Parcelable implementing classZackaryzacks
Working fine with custom objects. But, Is there a way to send list of data which is a custom object that extended Parcelable. If it's possible what modification should I make?Barcelona
H
-3
public static byte[] pack(Parcelable parcelable) {
    Parcel parcel = Parcel.obtain();
    parcelable.writeToParcel(parcel, 0);
    byte[] bytes = parcel.marshall();
    parcel.recycle();
    return bytes;
}

public static <T> T unpack(byte[] bytes, Parcelable.Creator<T> creator) {
    Parcel parcel = Parcel.obtain();
    parcel.unmarshall(bytes, 0, bytes.length);
    parcel.setDataPosition(0);
    return creator.createFromParcel(parcel);
}

MyObject myObject = unpack(new byte[]{/* bytes */}, MyObject.CREATOR);
Hawsepiece answered 16/3, 2014 at 23:20 Comment(1)
Please give a brief explanation of the code you posted so that it will be easier for OP to understand.Systemize

© 2022 - 2024 — McMap. All rights reserved.