简体   繁体   中英

Parcelable items disappearing when passing list of objects from service to activity via IPC

I'm writing an android application that runs a non-local service in order to fetch data from the internet. I have an activity that binds to said service and retrieves a list of Order objects in order to display them.

Something seems to be going wrong when passing the list from the service to the activity. Although this seems pretty straightforward to me.

The Problem

All the items in the list, but the item at index 1, are null values.

调试从活动接收的列表的视图

Debugging shows me that the service function has the correct list and also returns the correct list:

调试从服务发送的列表视图

This is the function in the service that returns the list:

public List<Order> getOrders() throws RemoteException {
    synchronized(service.orders) {
        // service.orders returns a hashmap<Integer, Order>
        // where the key is the ID of the order
        // The function returns a simple list, so we parse to an ArrayList
        List<Order> result = new ArrayList<Order>(service.orders.values()); 

        return result;
    }
}

This is the function in the Activity that calls the service and retrieves the list (where api is the result of binding to the service):

handler.post(new Runnable() {
    public void run() {
        try {
            List<Order> result = api.getOrders();

            displayOrders(result);

        } catch (Throwable t) {
            Log.e(TAG, "Error while updating the UI with orders", t);
        }
    }
});

This has got me totally stumped, since I also have an activity to view customers and a function on the service that returns a list of customers, and that works flawlessly. The major difference between the two is that Customer doesn't have any custom object properties, while Order has a few.

Edit: Added Parcelable implementation for Order class (simplified by removing most of the primitive properties):

/*
* Parcelabe interface implementation
*/

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

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

public Order(Parcel source) {
    ID = source.readInt();
    OrderID = source.readInt();
    CustomerID = source.readInt();

    TotalAmount = source.readDouble();
    TotalProducts = source.readDouble();

    OrderDate = source.readString();
    InvoiceDate = source.readString();
    DeliveryDate = source.readString();

    // Custom objects
    Customer = source.readParcelable(Customer.class.getClassLoader());

    History = new ArrayList<OrderHistory>();
    source.readTypedList(History, OrderHistory.CREATOR);

    State = source.readParcelable(OrderState.class.getClassLoader());
}

public int describeContents() {
    return Order.class.hashCode();
}

public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(ID);
    dest.writeInt(OrderID);
    dest.writeInt(CustomerID);

    dest.writeDouble(TotalAmount);
    dest.writeDouble(TotalProducts);    

    dest.writeString(OrderDate);
    dest.writeString(InvoiceDate);
    dest.writeString(DeliveryDate);

    // Custom object
    dest.writeParcelable(Customer, flags);
    dest.writeParcelable(State, flags);
    dest.writeTypedList(History);
}

Edit: Added code for OrderList class:

public class OrderList extends ArrayList implements Parcelable {

/**
 * 
 */
private static final long serialVersionUID = 417326483896340670L;

public OrderList() {

}


public OrderList(Parcel in) {
    readFromParcel(in);
}


/*
 * Parcelabe interface implementation
 */

public OrderList(Collection<Order> values) {
    this.addAll(values);
}


@SuppressWarnings("unchecked")
public static final Parcelable.Creator<OrderList> CREATOR = new Parcelable.Creator<OrderList>() {
    public OrderList createFromParcel(Parcel in) {
        return new OrderList(in);
    }

    public OrderList[] newArray(int arg0) {
        return null;
    }

};

private void readFromParcel(Parcel in) {
    this.clear();

    //First we have to read the list size
    int size = in.readInt();

    //Reading remember that we wrote first the Name and later the Phone Number.
    //Order is fundamental

    for (int i = 0; i < size; i++) {
        Order o = new Order();
        o = in.readParcelable(Order.class.getClassLoader());
        this.add(o);
    }

}

public int describeContents() {
    return 0;
}

public void writeToParcel(Parcel dest, int flags) {
    int size = this.size();
    // We have to write the list size, we need him recreating the list
    dest.writeInt(size);

    // We decided arbitrarily to write first the Name and later the Phone Number.
    for (int i = 0; i < size; i++) {
        Order o = this.get(i);
        dest.writeParcelable(o, flags);
    }
}

}

Any pointers?

Please don't hesitate to ask for specific info if you need any!

The problem seems to be caused by the two Integer properties of the Order class. One of them is never initialised, and is therefor null. When writing that to the Parcel, it fails causing the entire function to fail, and causing null values to popup in the resulting list. Strange that this does not throw any exceptions.

Changing my Integer properties back to int fixed the problem (because int is never null). Since I really needed to maintain the Integer type, I fixed it by passing null values in the parcel as the value -1.

This comes down to:

public class Order implements Parcelable {
    public Integer ID;
    public Integer OrderID;

    public Order(Parcel source) {
        ID = source.readInt();
        if (ID.intValue() == -1) {
            ID = null;
        }

        OrderID = source.readInt();
        if (OrderID.intValue() == -1) {
            OrderID = null;
        }
    }

    public void writeToParcel(Parcel dest, int flags) {
        if (ID == null) {
            dest.writeInt(-1);
        } else {
            dest.writeInt(ID);
        }

        if (OrderID == null) {
            dest.writeInt(-1);
        } else {
            dest.writeInt(OrderID);
        }
    }
}

This is probably a deserialization problem. Can you show us the serialized response from the service (xml/json) ?

You'll have to provide some more code to be sure but you have to make sure every object you want to transfer between your service implements the Parcelable correctly.

An ArrayList for example does not implement the interface, you'll have to extend it and do the necessary plumbing to make it work.

Example of all this here.

尝试传递一系列订单。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM