как правильно реализовать Parcelable с помощью ArrayList‹Parcelable›?

У меня возникли проблемы с созданием моего класса Parcelable. Проблема в том, что я пытаюсь записать в посылку член класса, который является объектом ArrayList<Parcelable>. ArrayList — это Serializable, а объекты (ZigBeeDev) в списке — это Parcelable.

Вот соответствующий код:

package com.gnychis.coexisyst;

import java.util.ArrayList;
import java.util.Iterator;

import android.os.Parcel;
import android.os.Parcelable;

public class ZigBeeNetwork implements Parcelable {

    public String _mac;             // the source address (of the coordinator?)
    public String _pan;             // the network address
    public int _band;               // the channel
    ArrayList<Integer> _lqis;       // link quality indicators (to all devices?)
    ArrayList<ZigBeeDev> _devices;  // the devices in the network

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(_mac);
        out.writeString(_pan);
        out.writeInt(_band);
        out.writeSerializable(_lqis);
        out.writeParcelable(_devices, 0);  // help here
    }

    private ZigBeeNetwork(Parcel in) {
        _mac = in.readString();
        _pan = in.readString();
        _band = in.readInt();
        _lqis = (ArrayList<Integer>) in.readSerializable();
        _devices = in.readParcelable(ZigBeeDev.class.getClassLoader());  // help here
    }

    public int describeContents() {
        return this.hashCode();
    }

    public static final Parcelable.Creator<ZigBeeNetwork> CREATOR = 
            new Parcelable.Creator<ZigBeeNetwork>() {
        public ZigBeeNetwork createFromParcel(Parcel in) {
            return new ZigBeeNetwork(in);
        }

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

    //...
}

Я отметил два места "//помогите здесь", чтобы понять, как правильно написать посылку и как ее восстановить. Если ZigBeeDev равно Parcelable (проверено правильно), как мне это сделать правильно?


person gnychis    schedule 12.08.2011    source источник


Ответы (5)


Ты почти попал!

Вам просто нужно сделать:

public void writeToParcel(Parcel out, int flags) {
    out.writeString(_mac);
    out.writeString(_pan);
    out.writeInt(_band);
    out.writeSerializable(_lqis);
    out.writeTypedList(_devices);
}

private ZigBeeNetwork(Parcel in) {
    _mac = in.readString();
    _pan = in.readString();
    _band = in.readInt();
    _lqis = (ArrayList<Integer>) in.readSerializable();
    in.readTypedList(_devices, ZigBeeDev.CREATOR);
}

Это все!

Для вашего списка Integer вы также можете сделать:

out.writeList(_lqis);
_lqis = new ArrayList<>();
in.readList(_lqis Integer.class.getClassLoader());

Он должен работать.

person NitroG42    schedule 12.08.2011
comment
Для справки в будущем, и я не уверен, что это опечатка, которую никто не заметил, но ZigBeeDev.Creator должно быть ZigBeeDev.CREATOR. Я получал ошибку каждый раз, пока не понял, что есть два разных создателя, которых я мог бы использовать в своем собственном проекте. - person gatlingxyz; 25.03.2014
comment
@ NitroG42 Второй подход для чтения списка приводит к cannot convert from void to ArrayList<Integer> - person AlexAndro; 07.08.2014
comment
Мне также нужно было создать экземпляр массива раньше, например, мой код будет выглядеть так: _devices = new ArrayList‹ZigBeeDev›(); in.readTypedList(_devices, ZigBeeDev.Creator); - person sgarman; 19.08.2014
comment
@sgarman Нет необходимости создавать экземпляр массива, поэтому вы получите предупреждение: Аргумент явного типа ZigBeeDev можно заменить на ‹› Эта проверка сообщает обо всех новых выражениях с аргументами типа, которые можно заменить на ромбовидный тип ‹› - person crubio; 15.02.2016
comment
Подтвердите, что работаете с универсальным Hashtable, который использует типы примитивов (включая String) для любого из своих ключей или значений. - person Eido95; 23.01.2017

В моем случае in.readTypedList(_devices, ZigBeeDev.CREATOR); поставил мне NullPointerException на _devices. Итак, я использовал это:

_devices = in.createTypedArrayList(ZigBeeDev.CREATOR);
person osrl    schedule 14.02.2015
comment
fwiw - причина, по которой вы получали NPE, заключается в том, что если вы используете in.readTypedList(), вам нужно сначала создать новый ArrayList(), а затем передать его in.readTypedList(yourNewArrayList, YourObj.CREATOR), иначе он будет пытаться поместить данные только в нулевой список. - person rf43; 25.10.2015
comment
Да, это правильно. Я прочитал исходный код, прежде чем использовать его. Спасибо за дополнительную информацию, которую я забыл написать. - person osrl; 27.10.2015
comment
@osrl, когда мы следуем вашему решению, получил исключение java.lang.OutOfMemoryError: не удалось выделить 13893804 байта с 11004100 свободными байтами и 10 МБ до OOM - person Ajit Kumar Dubey; 10.02.2016
comment
В вашем массиве хранятся файлы или что-то большое? @Аджит - person osrl; 11.02.2016

Вы должны использовать writeList(List l) для своего список целых чисел и writeTypedList(List val) для списка ZigBeeDevices

person DoubleMalt    schedule 12.08.2011

В конструкторе вы должны использовать

_lqis = in.createTypedArrayList(ZigBeeDev.CREATOR);

И в "writeToParcel" используйте

out.writeTypedList(_lqis);
person Anton Smirnov    schedule 01.10.2015

Немного поздно, но у меня тоже была эта проблема. После долгой траты времени я наткнулся на сайт parcelabler.com, который автоматически создает для вас посылки.

Это позволило мне очень легко создать вложенный участок со списком массивов внутри и сэкономило мне много времени.

По сути, веб-сайт работает следующим образом: вы вводите свой объект с ArrayList в нем, и он автоматически добавляет необходимые методы, чтобы сделать его разделяемым (чтение из пакета, запись в пакет, описание содержимого и создатель пакета генерируются автоматически). Это особенно полезно при создании сложных участков, таких как заданный здесь вопрос, которые содержат вложенные участки, массивы и списки.

РЕДАКТИРОВАТЬ: Также IntelliJ IDEA и Android Studio имеют для этого плагины, которые делают то же самое, что и указанный веб-сайт:

Эти плагины генерируют шаблонный код Android Parcelable на основе полей в классе.

person JFreeman    schedule 04.02.2019