通过 IPC 将对象列表从服务传递到活动时可打包项目消失

发布于 2024-12-01 09:49:41 字数 4476 浏览 7 评论 0原文

我正在编写一个运行非本地服务的 Android 应用程序,以便从互联网获取数据。我有一个活动绑定到所述服务并检索 Order 对象列表以显示它们。

将列表从服务传递到活动时似乎出了问题。尽管这对我来说似乎很简单。

问题

列表中的所有项目(索引 1 处的项目除外)均为空值。

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

调试显示服务函数具有正确的列表,并且还返回正确的列表:

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

这是服务中返回列表的函数:

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;
    }
}

这​​是函数在调用服务并检索的 Activity 中列表(其中 api 是绑定到服务的结果):

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);
        }
    }
});

这让我完全困惑了,因为我还有一个查看客户的活动和一个返回客户列表的服务函数,并且工作完美。两者之间的主要区别在于,Customer 没有任何自定义对象属性,而 Order 有一些。

编辑:为 Order 类添加了 Parcelable 实现(通过删除大部分原始属性进行简化):

/*
* 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);
}

编辑:为 OrderList 类添加了代码:

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);
    }
}

}

有任何指针吗?

如果您需要任何具体信息,请随时询问!

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.

Debug view of the received list from activity

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

Debug view of the list to send from the service

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

番薯 2024-12-08 09:49:41

该问题似乎是由 Order 类的两个 Integer 属性引起的。其中之一从未初始化,因此为空。将其写入 Parcel 时,它会失败,导致整个函数失败,并导致结果列表中弹出空值。奇怪的是这并没有抛出任何异常。

将我的 Integer 属性更改回 int 解决了问题(因为 int 永远不会为 null)。由于我确实需要维护 Integer 类型,因此我通过在包中传递空值作为值 -1 来修复它。

这归结为:

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);
        }
    }
}

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);
        }
    }
}
月光色 2024-12-08 09:49:41

这可能是一个反序列化问题。您能否向我们展示来自服务的序列化响应 (xml/json)?

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

少女的英雄梦 2024-12-08 09:49:41

您必须提供更多代码才能确定,但​​您必须确保要在服务之间传输的每个对象都正确实现了 Parcelable。

例如 ArrayList 没有实现该接口,您将必须扩展它并进行必要的管道才能使其正常工作。

这里是所有这些的示例。

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.

高冷爸爸 2024-12-08 09:49:41

尝试传递一系列订单。

Try passing an array of Orders.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文