Wednesday, April 24, 2013

Parcelable versus Serializable

In this post I'm going to talk about the differences between Parcelables and Serializables.

Android Activities are great, aren't they? They allow you to structure your app in a nice and easy way. Switching between two Activities is also really easy. Just write this.startActvitiy(intent) somewhere in your first Activity and you're done.
There's only one thing that's not so easy to do, and that's passing data between these two Activities. If we want to pass data we have to put it in an Intent or a Bundle. This is quite easy for primitive classes such as String or int, but it's a bit harder for other (custom) objects.

If you have some experience in Java, you probably know something about 'serialization'. Since we're using Java in our Android app, we could let our object implement Serializable and we're done, right? Well, not quite. Android provides us with another interface called Parcelable to do this and there's a reason why.

Serializable

First of all let's have a look at our TestObject that implements Serializable.
public class TestObject implements Serializable{



 private static final long serialVersionUID = 643301981519798569L;

 private String mString;

 private int mInt;

 private List<String> mList;

 

 public TestObject() {

  this.mString = "This is a String";

  this.mInt = 777;

  mList = new ArrayList<String>();

  for(int i=0; i<100; i++){

   mList.add(String.valueOf(i));

  }

 }

    //Getters and Setters...

}

The only thing we had to do to make sure TestObject could be passed with an Intent or Bundle, was implementing it with java.io.Serializable and add a generated serialVersionUID. Now let's have a look at the same class but as a Parcelable.

Parcelable

This is our TestObject, implementing android.os.Parcelable.

public class TestObject implements Parcelable{



 private String mString;

 private int mInt;

 private List<String> mList;



 public TestObject() {

  this.mString = "This is a String";

  this.mInt = 777;

  mList = new ArrayList<String>();

  for(int i=0; i<100; i++){

   mList.add(String.valueOf(i));

  }

 }

 

 public TestObject(Parcel in) {

  mString = in.readString();

  mInt = in.readInt();

  mList = new ArrayList<String>();

  in.readStringList(mList);

 }



 @Override

 public int describeContents() {

  return 0;

 }



 @Override

 public void writeToParcel(Parcel dest, int flags) {

  dest.writeString(mString);

  dest.writeInt(mInt);

  dest.writeStringList(mList);

  

 }

 

 public static final Parcelable.Creator<TestObject> CREATOR = new Parcelable.Creator<TestObject>() {

        public TestObject createFromParcel(Parcel in) {

            return new TestObject(in); 

        }



        public TestObject[] newArray(int size) {

            return new TestObject[size];

        }

    };

    

    //Getters and Setters...

}
The first thing we notice here is that our class just became a lot bigger. As you can see we have to override two methods, write a Parcelable.Creator and write a new Constructor. Why should you go through all this trouble if you can just simple use Serializable instead? The answer is performance.

Parcelable splits your object up into primitives, sends those primitives and rebuilds the object afterwards. By doing this, it should run a lot faster. Serializable creates a lot of temporary objects and this causes quite some garbage collection, which should always be avoided, especially on mobile devices.

Putting it to the test

Of course, I ran a small test on this. I created an instance of TestObject, added it to an Intent, started another Activity and took our TestObject out of the Intent. I used TraceView for to check how long this process took for Parcelable and Serializable.
Here's our result for using the Serializable interface:


So we can see this whole process took 248ms. 
Now let's have a look at the results of using the Parcelable interface:

As you can see, for only this one object, the process was completed in less than half of the time for our first way. And let's not forget, this is the whole process of switching to another Activity, not just writing and reading the object!

Conclusion

Parcelable works a lot faster than Serializable and is the best way to go. But if we don't need to be faster, and it's possible to just use Serializable (e.g. android.graphics.Bitmap causes problems), just use Serializable and you don't have to bother about anything anymore.

Important notes:

  • Read from the Parcel in the same order that you wrote to it
  • Don't use raw Creators (specify by adding <TestObject> in this example)