Элементы Parcelable исчезают при передаче списка объектов из службы в активность через IPC

Я пишу приложение для 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 есть несколько.

Изменить: добавлена ​​реализация Parcelable для класса Order (упрощена за счет удаления большинства примитивных свойств):

/*
* 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:

открытый класс OrderList расширяет ArrayList реализует 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);
    }
}

}

Любые указатели?

Пожалуйста, не стесняйтесь спрашивать конкретную информацию, если она вам нужна!


person Bram Vandenbussche    schedule 25.08.2011    source источник
comment
как сказал ReggieBE, вероятно, что-то связанное с сериализацией, дайте нам еще немного кода...   -  person Sander Versluys    schedule 25.08.2011
comment
Опубликуйте класс Order или, по крайней мере, биты разделения.   -  person dmon    schedule 25.08.2011
comment
также по умолчанию ArrayList не реализует Parcelable, вам придется самостоятельно расширять этот класс.   -  person Sander Versluys    schedule 25.08.2011
comment
Я могу следовать этому последнему, но я также пытался передать карту (с общим определением и без него), и возникает та же проблема. Добавит реализацию Parcelable для класса Order.   -  person Bram Vandenbussche    schedule 25.08.2011
comment
и не только класс Order, но и для пользовательского Arraylist, например, CustomersList расширяет ArrayList‹Customer›, реализует Parcelable   -  person Sander Versluys    schedule 25.08.2011


Ответы (4)


Проблема, по-видимому, вызвана двумя свойствами Integer класса Order. Один из них никогда не инициализируется и поэтому равен нулю. При записи этого в Parcel происходит сбой, что приводит к сбою всей функции и появлению нулевых значений в результирующем списке. Странно, что это не вызывает никаких исключений.

Изменение моих свойств Integer обратно на int устранило проблему (потому что int никогда не бывает нулевым). Так как мне очень нужно было сохранить тип 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);
        }
    }
}
person Bram Vandenbussche    schedule 26.08.2011

Вероятно, это проблема десериализации. Можете ли вы показать нам сериализованный ответ службы (xml/json)?

person Youri    schedule 25.08.2011
comment
Сериализация не проблема. Служба извлекает данные из Интернета, когда я отлаживаю данные, которые она собирается вернуть в действие, все свойства заполнены правильно. Я предполагаю, что вы ошибочно принимаете сервис за веб-сервис. Служба, о которой я говорю, является службой Android, как определено здесь: developer.android .com/reference/android/app/Service.html - person Bram Vandenbussche; 25.08.2011
comment
Да, но Android выполняет сериализацию через интерфейс Parcelable и использует его для передачи данных с намерениями и, следовательно, между действиями и/или службами... - person Sander Versluys; 25.08.2011
comment
Ах, вот что он имел в виду. Я думал, что он имел в виду десериализацию из веб-сервиса (xml) в объекты. - person Bram Vandenbussche; 26.08.2011

Вам нужно будет предоставить еще немного кода, чтобы быть уверенным, но вы должны убедиться, что каждый объект, который вы хотите передать между вашим сервисом, правильно реализует Parcelable.

Например, ArrayList не реализует интерфейс, вам придется расширьте его и сделайте необходимую сантехнику, чтобы заставить его работать.

Пример всего этого здесь.

person Sander Versluys    schedule 25.08.2011
comment
Добавлен класс OrderList, который расширяет ArrayList, как в примере, который вы мне дали, но это все равно ничего не меняет. Я могу предоставить вам полный исходный код, если хотите? - person Bram Vandenbussche; 26.08.2011

Попробуйте передать массив Orders.

person Youri    schedule 26.08.2011