Напишите подкласс Parcelable для другого Parcel

У меня есть класс, реализующий интерфейс Parcelable:

class A implements Parcelable {

}

У меня есть еще один класс B, который содержит объект A в качестве переменной экземпляра. В writeToPacel внутри класса B я хочу записать объект B в Parcel:

class B implements Parcelable{

    public void writeToParcel(Parcel dest, int flags) {
        dest.write ??? 
    }
}

Как я могу написать и прочитать это?


person user4o01    schedule 02.09.2012    source источник
comment
Где A object внутри B?   -  person iTurki    schedule 03.09.2012


Ответы (3)


class B implements Parcelable{
//lets assume you have A as a data member 

A obj;
public void writeToParcel(Parcel dest, int flags) {

        dest.writeParcelable(obj , flags);

    }
}

если вы хотите прочитать это, используйте это

 obj = in.readParcelable(A.class.getClassLoader());
person confucius    schedule 02.09.2012
comment
Кастинг не нужен :) - person pablisco; 10.07.2014
comment
Можно еще точнее: obj = (A) in.<A>readParcelable(A.class.getClassLoader()); - person caw; 09.12.2014
comment
Кастинг вообще не требуется! - person sud007; 29.09.2016

Лучший способ справиться с этим, избегая рефлексии, — просто вызвать статического создателя в целевом типе следующим образом:

this.amazingObject = AmazingObject.CREATOR.createFromParcel(in);

и запишите его в Parcelable с помощью this.amazingObject.writeToParcel(Parcel, int)

Внутри при вызове readParcelable(ClassLoader) происходит следующее:

public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
    Parcelable.Creator<T> creator = readParcelableCreator(loader);
    if (creator == null) {
        return null;
    }
    if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
        return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
    }
    return creator.createFromParcel(this);
}

Как вы можете видеть, последний вызов этого метода просто вызывает правильный Creator, но внутри readParcelableCreator есть много размышлений, которых мы можем избежать, просто вызвав его напрямую.

Эти служебные вызовы могут быть полезны:

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

public class Parcels {

    public static void writeBoolean(Parcel dest, Boolean value) {
        dest.writeByte((byte) (value != null && value ? 1 : 0));
    }

    public static Boolean readBoolean(Parcel in){
        return in.readByte() != 0;
    }

    public static void writeParcelable(Parcel dest, int flags, Parcelable parcelable) {
        writeBoolean(dest, parcelable == null);
        if (parcelable != null) {
            parcelable.writeToParcel(dest, flags);
        }
    }

    public static <T extends Parcelable> T readParcelable(Parcel in, Parcelable.Creator<T> creator) {
        boolean isNull = readBoolean(in);
        return isNull ? null : creator.createFromParcel(in);
    }

}
person pablisco    schedule 15.09.2014
comment
Выдает исключение, когда объект имеет значение null, а readParcelable корректно обрабатывает эту ситуацию. - person dragoon; 21.12.2014
comment
@dragoon Какое у тебя исключение? - person pablisco; 27.12.2014
comment
В итоге я использую свою собственную Parcel Util, но спасибо за вдохновение! - person Juan Saravia; 13.12.2015

Линия:

obj = (A)in.readParcelable(A.class.getClassLoader());

следует изменить на:

obj = (A)in.readParcelable(B.class.getClassLoader());

Я столкнулся с той же проблемой и сделал несколько поисков в Google, многие веб-страницы или учебники предлагают использовать A.class.getClassLoader(), потому что мы приводим к A, но на самом деле это НЕПРАВИЛЬНО, потому что вы получите нулевое значение, мы должны использовать B.class.getClassLoader(), потому что codes are INSIDE class B. Я просто не знал, почему, но таким образом он может получить правильный объект A.

Добро пожаловать, чтобы прокомментировать и проверить!

person Alison    schedule 07.02.2014