我有一些实现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's 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 :据我所知,它在以下位代码(来自Parcel's source)失败了:
Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader);
为什么找不到课程?它既存在又实现Parcelable
。
答案 0 :(得分:80)
因为在“回答”中没有回答,但在评论中我会发回答: 正如@ Max-Gontar指出的那样,你应该使用LocationType.class.getClassLoader()来获取正确的ClassLoader并摆脱ClassNotFound异常,即:
in.readParceleable(LocationType.class.getClassLoader());
答案 1 :(得分:34)
我在以下设置中遇到了同样的问题:某个处理程序创建了一个Message并通过Messenger将其发送到远程服务。
消息包含一个Bundle,我放置了我的Parcelable后代:
final Message msg = Message.obtain(null, 0);
msg.getData().putParcelable("DOWNLOADFILEURLITEM", downloadFileURLItem);
messenger.send(msg);
当远程服务尝试取消选中时,我遇到了同样的异常。在我的情况下,我监督了远程服务确实是一个单独的操作系统进程。因此,我必须设置当前的类加载器以供服务端的取消分析过程使用:
final Bundle bundle = msg.getData();
bundle.setClassLoader(getClassLoader());
DownloadFileURLItem urlItem = (DownloadFileURLItem)
bundle.getParcelable("DOWNLOADFILEURLITEM");
Bundle.setClassLoader设置用于加载相应Parcelable类的类加载器。在远程服务中,您需要将其重置为当前的类加载器。
答案 2 :(得分:9)
我发现问题是我没有将我的应用程序ClassLoader传递给解组函数:
in.readParceleable(getContext().getClassLoader());
而不是:
in.readParceleable(null);
OR
in.readParceleable(MyClass.class.getClassLoader());
答案 3 :(得分:8)
在这里加上我的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();
}
顺便提一下,作者这样做了,但有一天它可能对某人有所帮助。
答案 4 :(得分:6)
我对Parcelable不是很熟悉,但是如果它类似于Serialization,那么每次调用写一个实现该接口的对象都会导致对writeToParcel()的递归调用。因此,如果调用堆栈中的某些内容失败或写入空值,则可能无法正确构造发起调用的类。
尝试: 跟踪writeToParcel()调用堆栈,通过从第一次调用writeToParcel()开始的所有类,并验证是否正确发送了所有值。
答案 5 :(得分:6)
我也得到了ClassNotFoundException并且在这里发布了我的解决方案答案,这使我找到了正确的方向。我的情况是我有嵌套的parcelable对象。对象A包含Object B的ArrayList。两者都实现了Parcelable。 在A类中编写B对象列表:
@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());
}
谢谢!
答案 6 :(得分:5)
而不是使用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();
}
答案 7 :(得分:2)
我有同样的问题并以非常愚蠢的方式解决它,我不知道它是否完全被称为解决方案。
假设您要将此课程传递给其他活动
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();
}
}
多数民众赞成当我改变了:
dest.writeString(name);
dest.writeInt(age);
到
dest.writeInt(age);
dest.writeString(name);
问题解决了??? !!!!
答案 8 :(得分:0)
如果你有一个具有List对象类型属性的Object,你应该在读取属性时传递类加载器,例如:
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接口很重要。
答案 9 :(得分:0)
由于缺少构造函数,因此出现了此异常。所有实现Parcelable的类都必须执行相同的操作:
// add new constructor
@RequiresApi(Build.VERSION_CODES.N)
private LocationType(Parcel dest, ClassLoader loader) {
super(dest, loader);
locid = dest.readInt();
desc = dest.readString();
dir = dest.readString();
lat = dest.readDouble();
lng = dest.readDouble();
}
public static final Creator<LayoverType> CREATOR = new ClassLoaderCreator<LayoverType>() {
// add createFromParcel method with ClassLoader
@Override
public LayoverType createFromParcel(Parcel in, ClassLoader loader)
{
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? new LayoverType(in, loader) : new LayoverType(in);
}
public LayoverType createFromParcel(Parcel in) {
// call other createFromParcel method.
return createFromParcel(in, null);
}
public LayoverType[] newArray(int size) {
return new LayoverType[size];
}
};