I was recently writing a Parcelable class which contained a List of other Parcelable objects within, and noticed there are two ways to read and write these to Parcel. There are a couple of interesting differences between them:

parcel.writeTypedList(List<? extends Parcelable> list)

parcel.createTypedArrayList(Parcelable.Creator creator) parcel.writeList(List list)

parcel.readList(List outList, ClassLoader loader)

At first glance, option one seems like the better approach since it’s strongly typed, whereas the second option just uses a raw List type. It should also be faster since you’re providing the Parcelable.Creator instance directly, while the second option will require reflection to look up the class and find its Creator instance.

However, one important distinction between the two comes into play if you have Parcelable types which include subclasses (i.e. BaseClass implements Parcelable, SubClass extends BaseClass). If you write a List<BaseClass> (which could also include SubClass instances) using writeTypedList(), then pass in BaseClass.CREATOR to read back in the List<BaseClass>, any behavior or data associated with SubClass will be lost!

For a contrived example, say you have a class structure like this:

class BaseClass implements Parcelable {

private final int mBaseValue; BaseClass(int baseValue) {

mBaseValue = baseValue;

} int getValue() {

return mBaseValue;

} // Boilerplate Parceling code omitted

}

and a subclass:

class SubClass extends BaseClass {

private final int mSubValue; SubClass(int baseValue, int subValue) {

super(baseValue);

mSubValue = subValue;

} @Override

int getValue() {

return super.getValue() + mSubValue;

} // Boilerplate Parceling code omitted

}

Parceling a List<BaseClass> using writeTypedList() will give the following behavior:

BaseClass instance = new SubClass(5, 10); // instance.getValue() == 15 here. Parcel p = Parcel.obtain();

p.writeTypedList(Collections.singletonList(instance));

p.setDataPosition(0);

List<BaseClass> list = p.createTypedArrayList(BaseClass.CREATOR); instance = list.get(0); // instance.getValue() is now 5! It was created using the

// BaseClass.CREATOR, which only reads in mBaseValue.

Now, if you instead use writeList():

BaseClass instance = new SubClass(5, 10); // instance.getValue() == 15 here. Parcel p = Parcel.obtain();

List<BaseClass> list = Collections.singletonList(instance);

p.writeInt(list.size());

p.writeList(list);

p.setDataPosition(0);

List<BaseClass> readList = new ArrayList<>(p.readInt());

p.readList(readList, BaseClass.class.getClassLoader()); instance = readList.get(0); // instance.getValue() == 15 here too, as writeList() internally

// uses writeValue() which, for Parcelable types, stores the name

// of the class as well, which will then be used to resolve the

// specific Parcelable.Creator instance that is needed.

So is it always best to use option 2? Not necessarily. I did some rough benchmarking where I wrote and read in a list containing 5,000 BaseClass instances 5,000 times, using both methods.

Using writeTypedList():

Iterations: 5,000. Total time = 34,242 ms. Average = 6 ms. Using writeList():

Iterations: 5,000. Total = 195,917 ms. Average = 39 ms.

So for this particular example, using writeTypedList() is more than 6 times faster than using writeList(). However, it’s hopefully rare that you would ever be writing out such a large data set to a Parcel, so the difference in performance for general cases is probably not that large.

In conclusion, I would suggest that if you know the specific type of all the instances (i.e. your Parcelable type cannot be subclassed) then you should probably write it as a typed list for performance. If your Parcelable types can be extended, then you should definitely use the raw writeList() method, or you’ll be in for some unexpected behavior.