Android parcelable tutorial: List and inner class

When we want to pass objects between two components in Android, these objects have to implements Android Parcelable interface.Parcelable Android is a serialization and deserialization mechanism as we are used in Java. This post describes how we can use Parcelable interface to pass objects between two Android Activity.
We talked about some basic concepts of Parcelable in Android, in this post we will analyse some more complex example and we will look how we can parcel a List of objects or parcel a class that contains inner class.

Android parcelable tutorial using class and list

Android Parcel object

We know that if we want that Android OS can “serialize” an object it must implement Parcelable interface. To make an object parcelable we have to implements two methods defined in Parcelable interface:

Moreover, we have to provide Parcelable.Creator that is used to create an instance of the class from the Parcel data.
So let us suppose we have a simple class that contains a contact info:
public class ContactInfo {

  private String name;
  private String surname;
  private int idx;

  // get and set methods
}
So to make this object parcelable we have:
public class ContactInfo implements Parcelable {

  private String name;
  private String surname;
  private int idx;

  // get and set method

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(name);
    dest.writeString(surname);
    dest.writeInt(idx);
  }

  // Creator
  public static final Parcelable.Creator CREATOR
                      = new Parcelable.Creator() {
      public ContactInfo createFromParcel(Parcel in) {
          return new ContactInfo(in);
      }

     public ContactInfo[] newArray(int size) {
       return new ContactInfo[size];
    }
  };

  // "De-parcel object
  public ContactInfo(Parcel in) {
    name = in.readString();
    surname = in.readString();
    idx = in.readInt();
  }
}

As you can notice we have implemented all the requested method. So the android parcel operation is very simple because in the writeToParcel method we simply write all the class attributes and in the Parcel.Creator we read the parcel data. The creator calls a constructor passing Parcel object and here in the constructor we initialise the class attributes.
So now we are ready to pass this object from a caller activity to a receiver activity: in this case the in the caller activity (MainActivity):

Intent i = new Intent(MainActivity.this, ActivityB.class);
// Contact Info
ContactInfo ci = createContact("Francesco", "Surviving with android", 1);
i.putExtra("contact", ci);

while in the receiver activity we have:

Intent i = getIntent();
ContactInfo ci = i.getExtras().getParcelable("contact");
tv.setText(ci.toString()); // tv is a TextView instance
android parcelable object android parcelable

 

Android Parcelable List

By now, we used a simple example, now we want to create something more complex that uses Android parcelable. Instead using a simple class, we parcel a list of contact.
Now we have that our class is already parcelable, so it is simple; in the caller activity we have:
List<ContactInfo> cList = createContactList();

i.putParcelableArrayListExtra("contact", (ArrayList) cList);

while in the called activity:

<ContactInfo> ciArr = (List) i.getParcelableArrayListExtra("contact"); 

Android Parcel inner class

To parcel an class that contains an inner class we have to modify slightly the code. For example, let us suppose we have a inner class in our ContactInfo that contains the address:

public class ContactInfo implements Parcelable {

  private String name;
  private String surname;
  private int idx;
  private Address address;

  ...
  // Inner class
  public static class Address {
    private String street;
    private String city;
    private int number;

    // get and set methods
  }
}

Now, the first thing is making the inner class parcel able:

 // Inner class
public static class Address implements Parcelable {
  private String street;
  private String city;
  private int number;

  public Address() {}

   @Override
   public int describeContents() {
     return 0;
   }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(street);
   dest.writeString(city);
   dest.writeInt(number);
}

// Creator
public static final Parcelable.Creator
    CREATOR = new Parcelable.Creator() {
      public Address createFromParcel(Parcel in) {
        return new Address(in);
      }  

     public Address[] newArray(int size) {
       return new Address[size];
     }
  };

  // "De-parcel object
  private Address(Parcel in) {
    street = in.readString();
    city = in.readString();
     number = in.readInt();
  }
}

Notice that the inner class is now static otherwise it is not parcelable, second in the outer class:

public class ContactInfo implements Parcelable {

  private String name;
  private String surname;
  private int idx;
  private Address address;

   ....
  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(name);
    dest.writeString(surname);
    dest.writeInt(idx);

   // Add inner class
   dest.writeParcelable(address, flags);
  }

  // "De-parcel object
  public ContactInfo(Parcel in) {
   name = in.readString();
   surname = in.readString();
   idx = in.readInt();

    address = (Address) in.readParcelable(Address.class.getClassLoader());
}

At line 30 to unparcel the inner class we used the class loader

Running the example, we have:android parcelable inner class

Source code available @github

In this post, you gained a knowledge about android parcelable concept in android and how to use it to pass data.

  • Great! 🙂

  • This is not the most efficient way to parcel/unparcel an inner class because it requires writing the class metadata when parceling and playing with the classLoader when unparceling. In some cross-process scenarios the unparceling may also fail. In general I recommend this instead:

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(name);
    dest.writeString(surname);
    dest.writeInt(idx);

    // Add inner class
    address.writeToParcel(dest, flags);
    }

    // De-parcel object
    private ContactInfo(Parcel in) {
    name = in.readString();
    surname = in.readString();
    idx = in.readInt();

    address = Address.CREATOR.createFromParcel(in);

    }

    It's also recommended to make the Parcel constructor private so that only the CREATOR can use it.