Задача unmarshalling parcelables
У меня есть несколько классов, которые реализуют Parcelable, и некоторые из этих классов содержат друг друга как свойства. Я собираю классы в Parcel, чтобы передать их между действиями. Маршаллинг их на участок прекрасно работает, но когда я пытаюсь их развязать, я получаю следующую ошибку:
...
AndroidRuntime E Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: schemas.Arrivals.LocationType
AndroidRuntime E at android.os.Parcel.readParcelable(Parcel.java:1822)
AndroidRuntime E at schemas.Arrivals.LayoverType.<init>(LayoverType.java:121)
AndroidRuntime E at schemas.Arrivals.LayoverType.<init>(LayoverType.java:120)
AndroidRuntime E at schemas.Arrivals.LayoverType$1.createFromParcel(LayoverType.java:112)
AndroidRuntime E at schemas.Arrivals.LayoverType$1.createFromParcel(LayoverType.java:1)
AndroidRuntime E at android.os.Parcel.readTypedList(Parcel.java:1509)
AndroidRuntime E at schemas.Arrivals.BlockPositionType.<init>(BlockPositionType.java:244)
AndroidRuntime E at schemas.Arrivals.BlockPositionType.<init>(BlockPositionType.java:242)
AndroidRuntime E at schemas.Arrivals.BlockPositionType$1.createFromParcel(BlockPositionType.java:234)
AndroidRuntime E at schemas.Arrivals.BlockPositionType$1.createFromParcel(BlockPositionType.java:1)
...
Класс LayoverType
(где он не работает):
public class LayoverType implements Parcelable {
protected LocationType location;
protected long start;
protected long end;
public LayoverType() {}
public LocationType getLocation() {
return location;
}
public void setLocation(LocationType value) {
this.location = value;
}
public long getStart() {
return start;
}
public void setStart(long value) {
this.start = value;
}
public long getEnd() {
return end;
}
public void setEnd(long value) {
this.end = value;
}
// **********************************************
// for implementing Parcelable
// **********************************************
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(location, flags);
dest.writeLong(start);
dest.writeLong(end );
}
public static final Parcelable.Creator<LayoverType> CREATOR = new Parcelable.Creator<LayoverType>() {
public LayoverType createFromParcel(Parcel in) {
return new LayoverType(in);
}
public LayoverType[] newArray(int size) {
return new LayoverType[size];
}
};
private LayoverType(Parcel dest) {
location = (LocationType) dest.readParcelable(null); // it failing here
start = dest.readLong();
end = dest.readLong();
}
}
Здесь класс LocationType
:
public class LocationType implements Parcelable {
protected int locid;
protected String desc;
protected String dir;
protected double lat;
protected double lng;
public LocationType() {}
public int getLocid() {
return locid;
}
public void setLocid(int value) {
this.locid = value;
}
public String getDesc() {
return desc;
}
public void setDesc(String value) {
this.desc = value;
}
public String getDir() {
return dir;
}
public void setDir(String value) {
this.dir = value;
}
public double getLat() {
return lat;
}
public void setLat(double value) {
this.lat = value;
}
public double getLng() {
return lng;
}
public void setLng(double value) {
this.lng = value;
}
// **********************************************
// for implementing Parcelable
// **********************************************
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt (locid);
dest.writeString(desc );
dest.writeString(dir );
dest.writeDouble(lat );
dest.writeDouble(lng );
}
public static final Parcelable.Creator<LocationType> CREATOR = new Parcelable.Creator<LocationType>() {
public LocationType createFromParcel(Parcel in) {
return new LocationType(in);
}
public LocationType[] newArray(int size) {
return new LocationType[size];
}
};
private LocationType(Parcel dest) {
locid = dest.readInt ();
desc = dest.readString();
dir = dest.readString();
lat = dest.readDouble();
lng = dest.readDouble();
}
}
Обновление 2. Насколько я могу сказать, что он не работает на следующем фрагменте кода (из Исходный источник):
Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader);
Почему он не может найти класс? Он существует и реализует Parcelable
.
Ответы
Ответ 1
Потому что на ответ не ответил "ответ", но в комментарии я отправлю ответ:
В качестве указателя @Max-Gontar вы должны использовать LocationType.class.getClassLoader(), чтобы получить правильный ClassLoader и избавиться от исключения ClassNotFound, т.е.:
in.readParceleable(LocationType.class.getClassLoader());
Ответ 2
У меня была такая же проблема со следующей установкой: какой-то обработчик создает сообщение и отправляет его через Messenger на удаленную службу.
Сообщение содержит пакет, в который я помещал своего потомственного потомка:
final Message msg = Message.obtain(null, 0);
msg.getData().putParcelable("DOWNLOADFILEURLITEM", downloadFileURLItem);
messenger.send(msg);
У меня было то же исключение, когда удаленная служба попыталась распараллелить. В моем случае я наблюдал за тем, что удаленная служба действительно является отдельным процессом os. Поэтому мне пришлось установить текущий загрузчик классов, который будет использоваться процессом unparcelling со стороны службы:
final Bundle bundle = msg.getData();
bundle.setClassLoader(getClassLoader());
DownloadFileURLItem urlItem = (DownloadFileURLItem)
bundle.getParcelable("DOWNLOADFILEURLITEM");
Bundle.setClassLoader устанавливает загрузчик классов, который используется для загрузки соответствующих классов Parcelable. В удаленном сервисе вам нужно reset это для текущего загрузчика классов.
Ответ 3
Я обнаружил, что проблема заключалась в том, что я не передавал свои приложения ClassLoader в функцию unmarshalling:
in.readParceleable(getContext().getClassLoader());
Вместо
in.readParceleable(null);
ИЛИ
in.readParceleable(MyClass.class.getClassLoader());
Ответ 4
Просто добавив свои 2 цента здесь, потому что я потерял больше половины дня, почесывая голову. Вы можете получить эту ошибку, если не ставите методы записи и читаете методы в том же порядке. Например, следующее неверно:
@Override
// Order: locid -> desc -> lat -> dir -> lng
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt (locid);
dest.writeString(desc);
dest.writeDouble(lat);
dest.writeString(dir);
dest.writeDouble(lng);
}
// Order: locid -> desc -> dir -> lat -> lng
private LocationType(Parcel dest) {
locid = dest.readInt();
desc = dest.readString();
dir = dest.readString();
lat = dest.readDouble();
lng = dest.readDouble();
}
Кстати, автор сделал это правильно, но однажды может помочь кому-то.
Ответ 5
Я не очень разбираюсь в Parcelable, но если это что-то вроде Serialization, каждый вызов для записи объекта, реализующего интерфейс, вызовет рекурсивный вызов writeToParcel(). Поэтому, если что-то по стеке вызовов терпит неудачу или записывает нулевое значение, класс, инициировавший вызов, может быть неправильно построен.
Try:
Отслеживайте стек вызовов writeToParcel() через все классы, начиная с первого вызова writeToParcel(), и убедитесь, что все значения отправляются правильно.
Ответ 6
Я тоже получил ClassNotFoundException и опубликовал свое решение bc, и ответы привели меня в правильном направлении. Мой сценарий заключается в том, что у меня есть вложенные объекты. Объект A содержит ArrayList объекта B. Оба реализуют Parcelable.
Запись списка объекта B в классе A:
@Override
public void writeToParcel(Parcel dest, int flags) {
...
dest.writeList(getMyArrayList());
}
Чтение списка в классе A:
public ObjectA(Parcel source) {
...
myArrayList= new ArrayList<B>();
source.readList(myArrayList, B.class.getClassLoader());
}
Спасибо!
Ответ 7
Вместо использования writeParcelable и readParcelable напрямую используйте writeToParcel и createFromParcel. Поэтому лучший код:
@Override
public void writeToParcel(Parcel dest, int flags) {
location.writeToParcel(dest, flags);
dest.writeLong(start);
dest.writeLong(end );
}
public static final Parcelable.Creator<LayoverType> CREATOR = new Parcelable.Creator<LayoverType>() {
public LayoverType createFromParcel(Parcel in) {
return new LayoverType(in);
}
public LayoverType[] newArray(int size) {
return new LayoverType[size];
}
};
private LayoverType(Parcel dest) {
location = LocationType.CREATOR.createFromParcel(dest);
start = dest.readLong();
end = dest.readLong();
}
Ответ 8
Ну, у меня была такая же проблема и решить ее очень глупо, что я не знаю, называется ли это вообще решением.
позволяет сказать, что у вас есть этот класс, который вы хотите передать другому мероприятию.
public class Person implements Parcelable,Serializable{
public String Name;
public int Age;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
public SeriesInfo(Parcel in) {
age= in.readInt(); //her was my problem as I have put age befor name
//while in the writeToParcel function I have defined
//dest.writeInt(age) after in.readString();???!!!!
name= in.readString();
}
}
Thats it Когда я изменил:
dest.writeString(name);
dest.writeInt(age);
к
dest.writeInt(age);
dest.writeString(name);
Проблема решена???!!!!
Ответ 9
Если у вас есть объект с свойством типа объектов List, вы должны передать загрузчик класса, когда вы читаете свойство, например:
public class Mall implements Parcelable {
public List<Outstanding> getOutstanding() {
return outstanding;
}
public void setOutstanding(List<Outstanding> outstanding) {
this.outstanding = outstanding;
}
protected Mall(Parcel in) {
outstanding = new ArrayList<Outstanding>();
//this is the key, pass the class loader
in.readList(outstanding, Outstanding.class.getClassLoader());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(outstanding);
}
public static final Parcelable.Creator<Mall> CREATOR = new Parcelable.Creator<Mall>() {
public Mall createFromParcel(Parcel in) {
return new Mall(in);
}
public Mall[] newArray(int size) {
return new Mall[size];
}
};
}
Примечание. Важно, чтобы класс Outstanding реализовал интерфейс Parceable.