Search code examples
javaandroidarraylistparcelable

How to pass object with List of other object between activities using Parcelable?


I have an object called Order which I want to pass between activities. Currently I am using Parcelable to do so.

public class Order implements Parcelable {

    private String email;

    private Long timestamp;

    private List<OrderItem> items;

    public Order() { }

    private Order(Parcel in) {
        email = in.readString();
        timestamp = in.readLong();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(email);
        if (timestamp == null) {
            dest.writeByte((byte) 0);
        } else {
            dest.writeByte((byte) 1);
            dest.writeLong(timestamp);
        }
        dest.writeTypedList(items);
    }

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

    public static final Creator<Order> CREATOR = new Creator<Order>() {
        @Override
        public Order createFromParcel(Parcel in) {
            return new Order(in);
        }

        @Override
        public Order[] newArray(int size) {
            return new Order[size];
        }
    };
    // Getters
    ...
}

The items field is a List of OrderItem objects which implement the Parcelable interface.

public class OrderItem implements Parcelable {

    private String orderedClothingId;

    private int quantity;

    public OrderItem() { }

    public OrderItem(String orderedClothingId, int quantity) {
        this.orderedClothingId = orderedClothingId;
        this.quantity = quantity;
    }

    private OrderItem(Parcel in) {
        orderedClothingId = in.readString();
        quantity = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(orderedClothingId);
        dest.writeInt(quantity);
    }

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

    public static final Creator<OrderItem> CREATOR = new Creator<OrderItem>() {
        @Override
        public OrderItem createFromParcel(Parcel in) {
            return new OrderItem(in);
        }

        @Override
        public OrderItem[] newArray(int size) {
            return new OrderItem[size];
        }
    };
}

Now to pass an Order object called order from one activity to another I do the following:

Intent intent = new Intent(mContext, ActivityTwo.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(ORDER_DETAIL_INTENT_EXTRA_KEY, order);            
mContext.startActivity(intent);

In ActivityTwo I collect the Order object like so:

Bundle data = getIntent().getExtras();
assert data != null;
mOrder = data.getParcelable(ORDER_DETAIL_INTENT_EXTRA_KEY);

However, when I log the items field contained in the Order object in ActivityTwo it is null. How do I pass the original non-null Order object between activities without the items list being null?


Solution

  • First you miss to read the array back with dest = in.readTypedList(emptyList, CREATOR);

    But second and more important, you need to write/read the same ammount of arguments, since you have a if in your writeToParcel you need the same when reading:

    private Order(Parcel in) {
        email = in.readString();
        if(in.readByte() == 1)
            timestamp = in.readLong(); //here to skip just like the writeToParcel
        in.readTypedList(items = new ArrayList<OrderItem>(), OrderItem.CREATOR);
    }
    
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(email);
        if (timestamp == null) {
            dest.writeByte((byte) 0);
        } else {
            dest.writeByte((byte) 1);
            dest.writeLong(timestamp);
        }
        dest.writeTypedList(items);
    }