Как сделать класс с вложенными объектами Parcelable

Я хотел бы сделать класс A Parcelable.

public class A {
    public String str;
    public ArrayList<B> list;
}

Это то, что я придумал до сих пор. Однако он падает с NullPointerException. Проблема заключается в этих двух операторах: dest.writeList(list); и in.readList(list, this.getClass().getClassLoader());. Я не могу понять, что делать отсюда :(

Класс А

public class A implements Parcelable {
    public String str;
    public ArrayList<B> list;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
        dest.writeList(list);
    }

    private A(Parcel in) {
        str = in.readString();
        in.readList(list, this.getClass().getClassLoader());
    }

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

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

Класс Б

public class B implements Parcelable {
    public String str;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

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

    private B(Parcel in) {
        str = in.readString();
    }

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

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

Спасибо за ваше время.


person Snæbjørn    schedule 06.01.2013    source источник


Ответы (7)


Наконец-то я понял, что вводить в Google :), и нашел этот Android, Как правильно использовать метод readTypedList в классе Parcelable?

Решение состояло в том, чтобы использовать вместо этого read-/writeTypedList. Я также инициализирую список массивов, чтобы избежать дальнейших исключений NullPointerException.

Класс А

public class A implements Parcelable {
    public String str;
    public ArrayList<B> list = new ArrayList<B>();

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
        dest.writeTypedList(list);
    }

    private A(Parcel in) {
        str = in.readString();
        in.readTypedList(list, B.CREATOR);
    }

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

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

Класс Б

public class B implements Parcelable {
    public String str;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

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

    private B(Parcel in) {
        str = in.readString();
    }

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

        public B[] newArray(int size) {
            return new B[size];
        }
    };
}
person Snæbjørn    schedule 06.01.2013
comment
Ах да, не пускала, а потом как-то забыла об этом :) - person Snæbjørn; 09.01.2013
comment
@Snæbjørn Спасибо, что поделились решением. - person Saro Taşciyan; 10.10.2013
comment
@Snæbjørn +1 за демонстрацию того, как создать разделяемый класс, содержащий непримитивные или настраиваемые типы. - person ripopenid; 07.12.2013
comment
Потрясающий пример. Могу я предложить вам исправить имена функций AcreateFromParcel в обоих классах? В классе A должен быть общедоступный A createFromParcel (отсутствует пробел), а в классе B должен быть общедоступный B createFromParcel. Да, это тривиально, но для новичков может быть проблематично. - person Miguel El Merendero; 18.02.2014

Если у вас есть только один объект Parcelable внутри вашего основного объекта Parcelable, не перечисляйте, как в случае принятого ответа. Тогда это будет примерно следующее:

Класс А

public class A implements Parcelable {
    public String str;
    public B objectB;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //The parcelable object has to be the first one
        dest.writeParcelable(objectB, flags);
        dest.writeString(str);
    }

    private A(Parcel in) {
        this.objectB = in.readParcelable(B.class.getClassLoader());
        str = in.readString();
    }

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

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

Класс Б

public class B implements Parcelable {
    public String str;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

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

    private B(Parcel in) {
        str = in.readString();
    }

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

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

ВАЖНО: обратите внимание, что порядок, в котором вы пишете и читаете объект Parcelable, имеет значение. Ознакомьтесь с этим ответом для получения более подробной информации.

person Sami Eltamawy    schedule 21.04.2015

При записи на посылку

@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeString(name); //if String
    parcel.writeTypedList(assignedEmployees); //if List with custom class, eg. List<AssignedEmployee> assignedEmployees
    parcel.writeParcelable(checkin,i); //if custom class, eg. Checkin checkin;
    }

В Constructor для чтения обратно

 protected A(Parcel in) {
        name = in.readString();
        assignedEmployees = in.createTypedArrayList(AssignedEmployee.CREATOR);
        checkin = in.readParcelable(Checkin.class.getClassLoader());
    }

где AssignedEmployee, Checkin, где пользовательские классы, и он должен реализовывать Parcelable.

person Ebin Joy    schedule 28.07.2018

Просто нажмите ALT+ENTER и замените Parcelable, он реализует всю необходимую реализацию

person Dhruv Singh    schedule 06.06.2017
comment
Попробуйте этот ответ. Он выполняет всю работу автоматически. Вам не нужно писать ни одной строки кода. - person Alok Singh; 27.04.2020

Вы можете добавить плагин генератора кода Parcelable из префов, оттуда вы можете создать шаблонный код для парцеллирования, выполнив: - щелкните правой кнопкой мыши имя класса в модели - выберите "Создать" - выберите Parcelable

presto - ваша модель будет обновлена ​​с необходимым шаблонным кодом Parcelable.

person GordonW    schedule 30.08.2017

У меня была такая же проблема, вот общая версия

class Item<T : Parcelable> (val model: T, val index: Int ) : Parcelable {

    constructor(parcel: Parcel) :
        this(parcel.readParcelable(
          Item<T>::model.javaClass.classLoader),
          parcel.readInt()
        ) {}

    override fun writeToParcel(parcel: Parcel?, flag: Int) {
        parcel?.writeParcelable(model, 0)
        parcel?.writeInt(index)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Item<Parcelable>> {
        override fun createFromParcel(parcel: Parcel): Item<Parcelable> {
            return Item(parcel)
        }

        override fun newArray(size: Int): Array<Item<Parcelable>?> {
            return arrayOfNulls(size)
        }
    }
}
person Jocky Doe    schedule 20.12.2017

К сожалению, я использовал класс (BarEntry) из сторонней библиотеки, которую нельзя было разделить. Я решил свою проблему, пропустив через Intent массив из floats, а затем реконструировав свои BarEntry объекты на принимающей стороне.

Это неоптимально, но это может быть полезным процессом, если у кого-то есть подобные обстоятельства, когда создание объекта, способного к посылке, не вариант.

person JFreeman    schedule 25.01.2019