How to use Parcel in Android?

I’m trying to use Parcel to write and then read back a Parcelable. For some reason, when I read the object back from the file, it’s coming back as null.

public void testFoo() {
    final Foo orig = new Foo("blah blah");

    // Wrote orig to a parcel and then byte array
    final Parcel p1 = Parcel.obtain();
    p1.writeValue(orig);
    final byte[] bytes = p1.marshall();


    // Check to make sure that the byte array seems to contain a Parcelable
    assertEquals(4, bytes[0]); // Parcel.VAL_PARCELABLE


    // Unmarshall a Foo from that byte array
    final Parcel p2 = Parcel.obtain();
    p2.unmarshall(bytes, 0, bytes.length);
    final Foo result = (Foo) p2.readValue(Foo.class.getClassLoader());


    assertNotNull(result); // FAIL
    assertEquals( orig.str, result.str );
}


protected static class Foo implements Parcelable {
    protected static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
        public Foo createFromParcel(Parcel source) {
            final Foo f = new Foo();
            f.str = (String) source.readValue(Foo.class.getClassLoader());
            return f;
        }

        public Foo[] newArray(int size) {
            throw new UnsupportedOperationException();
        }

    };


    public String str;

    public Foo() {
    }

    public Foo( String s ) {
        str = s;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int ignored) {
        dest.writeValue(str);
    }


}

What am I missing?

  • App not compatible with tablet
  • Xamarin build action warning XA0101
  • Android run a Task Periodically
  • How to add section separators / dividers to a ListView?
  • Ontouch event of OnTouchListener gets called twice in android
  • Set android datepicker date limits
  • UPDATE: To simplify the test I’ve removed the reading and writing of files in my original example.

    Related posts:

    How do I change screen orientation in the Android emulator?
    push activity on the right when open drawer
    Android SDK Issues Ubuntu 10.04lts
    Android permissions: Phone Calls: read phone state and identity
    Android: how to check how much memory is remaining?
    Android two player game to be played in internet
  • Best way to secure Private REST API without user authentication for mobile app
  • defined xml layout in layout-land does not appear in android application
  • Showing custom View under swiped RecyclerView item
  • Why should a TypedArray be recycled?
  • Andengine fade in/out and alpha modifiers not working
  • Displaying emoticons in Android
  • 5 Solutions collect form web for “How to use Parcel in Android?”

    Ah, I finally found the problem. There were two in fact.

    1. CREATOR must be public, not protected. But more importantly,
    2. You must call setDataPosition(0) after unmarshalling your data.

    Here is the revised, working code:

    public void testFoo() {
        final Foo orig = new Foo("blah blah");
        final Parcel p1 = Parcel.obtain();
        final Parcel p2 = Parcel.obtain();
        final byte[] bytes;
        final Foo result;
    
        try {
            p1.writeValue(orig);
            bytes = p1.marshall();
    
            // Check to make sure that the byte stream seems to contain a Parcelable
            assertEquals(4, bytes[0]); // Parcel.VAL_PARCELABLE
    
            p2.unmarshall(bytes, 0, bytes.length);
            p2.setDataPosition(0);
            result = (Foo) p2.readValue(Foo.class.getClassLoader());
    
        } finally {
            p1.recycle();
            p2.recycle();
        }
    
    
        assertNotNull(result);
        assertEquals( orig.str, result.str );
    
    }
    
    protected static class Foo implements Parcelable {
        public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
            public Foo createFromParcel(Parcel source) {
                final Foo f = new Foo();
                f.str = (String) source.readValue(Foo.class.getClassLoader());
                return f;
            }
    
            public Foo[] newArray(int size) {
                throw new UnsupportedOperationException();
            }
    
        };
    
    
        public String str;
    
        public Foo() {
        }
    
        public Foo( String s ) {
            str = s;
        }
    
        public int describeContents() {
            return 0;
        }
    
        public void writeToParcel(Parcel dest, int ignored) {
            dest.writeValue(str);
        }
    
    
    }
    

    Beware! Dont use Parcel for serialization to a file

    Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.

    from http://developer.android.com/reference/android/os/Parcel.html

    I find that Parcelable is most often used in Android within data Bundles, but more specifically within a Handler that is sending and receiving messages. As an example, you might have an AsyncTask or a Runnable that needs to run in the background but post resulting data to the Main thread or Activity.

    Here’s a simple example. If I have a Runnable that looks like this:

    package com.example;
    
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    
    import com.example.data.ProductInfo;
    import com.google.gson.Gson;
    import com.google.gson.reflect.TypeToken;
    import com.squareup.okhttp.OkHttpClient;
    
    public class AsyncRunnableExample extends Thread {
        public static final String KEY = "AsyncRunnableExample_MSG_KEY";
    
        private static final String TAG = AsyncRunnableExample.class.getSimpleName();
        private static final TypeToken<ProductInfo> PRODUCTINFO =
                  new TypeToken<ProductInfo>() {
                  };
        private static final Gson GSON = new Gson();
    
        private String productCode;
        OkHttpClient client;
        Handler handler;
    
        public AsyncRunnableExample(Handler handler, String productCode)
        {
            this.handler = handler;
            this.productCode = productCode;
            client = new OkHttpClient();
        }
    
        @Override
        public void run() {
            String url = "http://someserver/api/" + productCode;
    
            try
            {
                HttpURLConnection connection = client.open(new URL(url));
                InputStream is = connection.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
    
                // Deserialize HTTP response to concrete type.
                ProductInfo info = GSON.fromJson(isr, PRODUCTINFO.getType());
    
                Message msg = new Message();
                Bundle b = new Bundle();
                b.putParcelable(KEY, info);
                msg.setData(b);
                handler.sendMessage(msg);
    
            }
            catch (Exception err)
            {
                Log.e(TAG, err.toString());
            }
    
        }
    }
    

    As you can see, this runnable takes a Handler in its constructor. This is called from some Activity like this:

    static class MyInnerHandler extends Handler{
            WeakReference<MainActivity> mActivity;
    
            MyInnerHandler(MainActivity activity) {
                mActivity = new WeakReference<MainActivity>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                MainActivity theActivity = mActivity.get();
                ProductInfo info = (ProductInfo) msg.getData().getParcelable(AsyncRunnableExample.KEY);
    
                // use the data from the Parcelable 'ProductInfo' class here
    
                }
            }
        }
        private MyInnerHandler myHandler = new MyInnerHandler(this);
    
        @Override
        public void onClick(View v) {
            AsyncRunnableExample thread = new AsyncRunnableExample(myHandler, barcode.getText().toString());
            thread.start();
        }
    

    Now, all that is left is the heart of this question, how you define a class as Parcelable. I’ve chosen a fairly complex class to show because there are some things you would not see with a simple one. Here is the ProductInfo class, which Parcels and unParcels cleanly:

    public class ProductInfo implements Parcelable {
    
        private String brand;
        private Long id;
        private String name;
        private String description;
        private String slug;
        private String layout; 
        private String large_image_url;
        private String render_image_url;
        private String small_image_url;
        private Double price;
        private String public_url;
        private ArrayList<ImageGroup> images;
        private ArrayList<ProductInfo> related;
        private Double saleprice;
        private String sizes;
        private String colours;
        private String header;
        private String footer;
        private Long productcode;
    
        // getters and setters omitted here
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeLong(id);
            dest.writeString(name);
            dest.writeString(description);
            dest.writeString(slug);
            dest.writeString(layout);
            dest.writeString(large_image_url);
            dest.writeString(render_image_url);
            dest.writeString(small_image_url);
            dest.writeDouble(price);
            dest.writeString(public_url);
            dest.writeParcelableArray((ImageGroup[])images.toArray(), flags);
            dest.writeParcelableArray((ProductInfo[])related.toArray(), flags);
            dest.writeDouble(saleprice);
            dest.writeString(sizes);
            dest.writeString(colours);
            dest.writeString(header);
            dest.writeString(footer);
            dest.writeLong(productcode);
        }
    
        public ProductInfo(Parcel in)
        {
            id = in.readLong();
            name = in.readString();
            description = in.readString();
            slug = in.readString();
            layout = in.readString();
            large_image_url = in.readString();
            render_image_url = in.readString();
            small_image_url = in.readString();
            price = in.readDouble();
            public_url = in.readString();
            images = in.readArrayList(ImageGroup.class.getClassLoader());
            related = in.readArrayList(ProductInfo.class.getClassLoader());
            saleprice = in.readDouble();
            sizes = in.readString();
            colours = in.readString();
            header = in.readString();
            footer = in.readString();
            productcode = in.readLong();
        }
    
        public static final Parcelable.Creator<ProductInfo> CREATOR = new Parcelable.Creator<ProductInfo>() {
            public ProductInfo createFromParcel(Parcel in) {
                return new ProductInfo(in); 
            }
    
            public ProductInfo[] newArray(int size) {
                return new ProductInfo[size];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    }
    

    The CREATOR is critical, as is the resulting constructor taking a Parcel. I included the more complex data types so you could see how to Parcel and unParcel Arrays of Parcelable objects. This is a common thing when using Gson to convert JSON into objects with children as in this example.

    To get a better understanding of the Parcel concept Try the below Link

    http://prasanta-paul.blogspot.com/2010/06/android-parcelable-example.html

    hope this helps 🙂

    I too had similar problem. only the following snippet from emmby and this helped me out.

        public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
            public Foo createFromParcel(Parcel source) {
                final Foo f = new Foo();
                f.str = (String) source.readValue(Foo.class.getClassLoader());
                return f;
            }
    
            public Foo[] newArray(int size) {
                throw new UnsupportedOperationException();
            }
    

    It should be kept in each of the class that implements Parcelable

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.