Проблема в реализации Parcelable, содержащего другой Parcelable

Я реализую класс Parcelable, в котором есть еще один Parcelable insde.

В классе OuterParcelable:

@Override
public void writeToParcel(Parcel dest, int flags) {
    Bundle tmp = new Bundle();

    tmp.putParcelable("innerParcelable", mParcelable);
    dest.writeBundle(tmp);

а потом:

public OuterParcelable(Parcel parcel) {
    super();

    Bundle b = parcel.readBundle();
    mParcelable = b.getParcelable("innerParcelable");

и:

    public OuterParcelable createFromParcel(Parcel in) {
        return new OuterParcelable(in);
    }

Когда я воссоздаю объект, используя приведенный выше код, я получаю:

 08-18 17:13:08.566: ERROR/AndroidRuntime(15520): Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: my.package.InnerParcelable

person pixel    schedule 18.08.2010    source источник


Ответы (2)


Чистый способ хранения непримитивных атрибутов в виде разделяемых, возможно нулевых, значений. Используйте Parcel.writeValue() и readValue() . См. комментарии в коде ниже:

public class MyParcelableClass implements Parcelable {
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(getIntegerAttribute()); // getIntegerAttribute() returns Integer
        dest.writeValue(getDoubleAttribute());
        dest.writeValue(getMyEnumAttribute()); // getMyEnumAttribute() returns a user defined enum
        dest.wrtieValue(getUserClassAttribute()); //UserClass must implement Parcelable in a similar fashion
    }

    private MyParcelableClass(Parcel in) {
        setIntegerAttribute((Integer)in.readValue(null)); //pass null to use default class loader. Ok for Integer, String, etc.
        setDoubleAttribute((Double)in.readValue(null)); //Cast to your specific attribute type
        setEnumAttribute((MyEnum)in.readValue(null));
        setUserClassAttribute((UserClass)in.readValue(UserClass.class.getClassLoader())); //Use specific class loader
    }

    @Override
    public int describeContents() ...

    public static final Parcelable.Creator<ParcelableLocationBean> CREATOR ...    
}

Работает как шарм. writeValue() и readValue() инкапсулируют работу с возможными значениями NULL и определением типа. Из джавадока:

public final void writeValue (Object v)
Объединить общий объект в пакет. Заданное значение Object в настоящее время может быть одного из следующих типов:
null, String, Integer, ...
String[], boolean[], ...
Любой объект, реализующий протокол Parcelable. ...

person Cléssio Mendes    schedule 03.01.2013

Почему вы помещаете значение в Bundle? Вы полностью реализовали возможность разделения в своем классе?

Собираемый скелет

public MyClass(Parcel in) {
    readFromParcel(in);
}

    //
// Parcelable Implementation
@Override
public int describeContents() {
    return 0;
}

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

private void writeObject(Parcel dest, Object obj) {
    if (obj != null) {
        dest.writeInt(1);
        dest.writeValue(obj);
    } else {
        dest.writeInt(0);
    }
}

public void readFromParcel(Parcel in) {
    aParcelableClass = in.readParcelable(ParcelableClass.class.getClassLoader());
}

private Object readObject(Parcel in) {
    Object value = null;

    if (in.readInt() == 1) {
        value = in.readValue(null); // default classloader
    }

    return value;
}

public static final Parcelable.Creator<MyClass> CREATOR = new Parcelable.Creator<MyClass>() {
    @Override
    public MyClass createFromParcel(Parcel source) {
        return new MyClass(source);
    }

    @Override
    public MyClass[] newArray(int size) {
        return new MyClass[size];
    }
};

Я добавил несколько вещей, чтобы упростить работу с нулевыми значениями, но принцип тот же. Вам нужны элементы @Override, конструктор и Creator.

Если вы собираетесь читать и писать посылки, у вас возникнут проблемы, если вы укажете null в качестве загрузчика классов.

person Cameron Lowell Palmer    schedule 02.08.2012
comment
Моя проблема заключалась в том, что я хотел вложить одну посылку в другую. А оказалось, что это невозможно. - person pixel; 02.08.2012
comment
Я делаю это все время. На самом деле приведенный выше фрагмент кода показывает запись посылки внутри посылки. - person Cameron Lowell Palmer; 02.08.2012
comment
У меня была та же проблема, что и с пикселем, я решил ее, внимательно изучив скелет, о котором сообщил Кэмерон Лоуэлл Палмер; критическая проблема заключалась в том, что я передавал загрузчик нулевого класса для чтения внутреннего объекта. Спасибо, Кэмерон, я проголосовал за ваш ответ. - person Giorgio Barchiesi; 04.11.2012