Saturday, 20 October 2018

How to use Android Parcelable to pass Objects between Activities

Android as a mobile platform, is more memory constrained. So app developers are pushed to write code that consumes less memory without compromising on performance. Even though Java provides several ways to accomplish works, it sometimes comes with lot of memory usage.

For example, unlike integers and strings, you can’t pass objects between activities. For this, you have to flatten the data.

There are two options available: Java’s Serializable interface and Android’s Parcelable interface. Which is better? We’ll look at each of them.

Serializable is a java marker interface with no methods, which helps serialize and deserialize Objects. Actually, ObjectInputStream and ObjectOutputStream are the classes that serialize the Object into a stream and deserialize back into an Object. The class that implements Serializable are meant to be serialized.

public class User implements Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

Since the User class implements Serializable, when we pass it between Activities using Bundle, the class gets serialized into a stream and in the receiver Activity it gets deserialized back into User.

Intent intent = new Intent(UserListActivity.this, UserDetailActivity.class);
intent.putExtra(user, user);
startActivity(intent);
User user = getIntent().getSerializableExtra(user);

The putExtra method serializes the User class into a stream and getSerializableExtra deserializes the stream into User.

Even Though it looks easy to implement this, there are some memory issues associated if the Object class stores lots of data. This serialization process creates a lot of temporary objects and since it also uses reflection, this process tends to be slow and causes more Garbage Collection.

A better way to do this is using Android’s Parcelable interface. It is an interface used to marshal and unmarshal Objects in Android. The main advantage of using Parcelable is it requires us to explicitly serialize the Objects, so there is no reflection involved and less garbage collection. It is said that Parcelable takes on the order of 10x less time to both serialize and deserialize, compared to Serializable.

To use Parcelable, just implement the interface and override the writeToParcel method. In this method, you explicitly write the data to Parcel, which is a container for all the data. You must also implement a non-null static field called CREATOR of type that implements the interface Parcelable.Creator.

A typical example of the User class is shown below:

public class User implements Parcelable {
private String name;
private int age;
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
}

As you can see we override the writeToParcel method to write the name and age to Parcel. This way the User is flattened. To deserialize, the CREATOR field’s createFromParcel returns a new instance of the Parcelable object, by initializing the variables from the Parcel.

Note that the values should be read from the Parcel in the same order they are written into it using writeToParcel.

To write an Arraylist of Objects into parcel, you can use parcel.writeList(objectName);
To read the ArrayList, use parcel.readArrayList(classLoader);

The main disadvantage is that you have to write all the boilerplate code yourself. But there are libraries you can use to make it easy. Parceler is such library that uses annotations to reduce boilerplate. Typically, to make a class Parcelable using this library, just add @Parcel to the class.

@Parcel
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

To pass the Object use

intent.putExtra("user", Parcels.wrap(user));

and to get the Object use

User user = Parcels.unwrap(getIntent().getParcelableExtra("user"));

You can find a demo of manually implementing Parcelable on my github page

1 Comment

  • I blog frequently and I seriously appreciate your information. This great article has really peaked my interest. I am going to take a note of your website and keep checking for new details about once per week. I subscribed to your Feed too.

Leave a Reply

Your email address will not be published. Required fields are marked *