Java 解组可打包物的问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1996294/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Problem unmarshalling parcelables
提问by Jeremy Logan
I've got a few classes that implement Parcelableand some of these classes contain each other as properties. I'm marshalling the classes into a Parcelto pass them between activities. Marshalling them TO the Parcel works fine, but when I try to unmarshall them I get the following error:
我有一些实现Parcelable 的类,其中一些类作为属性相互包含。我将这些类编组到一个包裹中,以便在活动之间传递它们。将它们编组到包裹中工作正常,但是当我尝试解组它们时,出现以下错误:
...
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.createFromParcel(LayoverType.java:112)
AndroidRuntime E at schemas.Arrivals.LayoverType.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.createFromParcel(BlockPositionType.java:234)
AndroidRuntime E at schemas.Arrivals.BlockPositionType.createFromParcel(BlockPositionType.java:1)
...
The LayoverType
class (where it's failing):
该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();
}
}
Here's the LocationType
class:
这是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();
}
}
Update 2: As far as I can tell it's failing at the following bit of code (from Parcel's source):
更新 2:据我所知,它在以下代码位失败(来自Parcel 的来源):
Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader);
Why is it not able to find the class? It both exists and implements Parcelable
.
为什么找不到类?它既存在又实现Parcelable
。
采纳答案by Ognyan
Because this was not answered in "answer" but in comment I will post an answer: As @Max-Gontar pointed you should use LocationType.class.getClassLoader() to get the correct ClassLoader and get rid of ClassNotFound exception, i.e.:
因为这在“答案”中没有得到回答,但在评论中我会发布一个答案:正如@Max-Gontar 指出的,你应该使用 LocationType.class.getClassLoader() 来获得正确的 ClassLoader 并摆脱 ClassNotFound 异常,即:
in.readParceleable(LocationType.class.getClassLoader());
in.readParceleable(LocationType.class.getClassLoader());
回答by mkamowski
I am not very familiar with Parcelable but if it's anything like Serialization each call to write an object that implements the interface will cause a recursive call to writeToParcel(). Therefore, if something along the call stack fails or writes a null value the class that initiated the call may not be constructed correctly.
我对 Parcelable 不是很熟悉,但是如果它类似于序列化,每次编写实现接口的对象的调用都会导致对 writeToParcel() 的递归调用。因此,如果调用堆栈中的某些内容失败或写入空值,则可能无法正确构造发起调用的类。
Try: Trace the writeToParcel() call stack through all the classes starting at the first call to writeToParcel() and verify that all the values are getting sent correctly.
尝试:从第一次调用 writeToParcel() 开始,通过所有类跟踪 writeToParcel() 调用堆栈,并验证所有值是否正确发送。
回答by mxcl
I found the problem was I was not passing my applications ClassLoader to the unmarshalling function:
我发现问题是我没有将我的应用程序 ClassLoader 传递给解组函数:
in.readParceleable(getContext().getClassLoader());
Rather than:
而不是:
in.readParceleable(null);
OR
或者
in.readParceleable(MyClass.class.getClassLoader());
回答by Andre Steingress
I had the same problem with the following setup: some handler creates a Message and sends its over a Messenger to a remote service.
我在以下设置中遇到了同样的问题:一些处理程序创建一个 Message 并通过 Messenger 将其发送到远程服务。
the Message contains a Bundle where I put my Parcelable descendant:
Message 包含一个 Bundle,我将 Parcelable 后代放在其中:
final Message msg = Message.obtain(null, 0);
msg.getData().putParcelable("DOWNLOADFILEURLITEM", downloadFileURLItem);
messenger.send(msg);
I had the same exception when the remote service tried to unparcel. In my case, I had overseen that the remote service is indeed a separate os process. Therefore, I had to set the current classloader to be used by the unparcelling process on the service side:
当远程服务试图解包时,我遇到了同样的异常。就我而言,我已经看到远程服务确实是一个单独的操作系统进程。因此,我必须设置当前类加载器以供服务端的解包过程使用:
final Bundle bundle = msg.getData();
bundle.setClassLoader(getClassLoader());
DownloadFileURLItem urlItem = (DownloadFileURLItem)
bundle.getParcelable("DOWNLOADFILEURLITEM");
Bundle.setClassLoader sets the classloader which is used to load the appropriate Parcelable classes. In a remote service, you need to reset it to the current class loader.
Bundle.setClassLoader 设置用于加载适当 Parcelable 类的类加载器。在远程服务中,您需要将其重置为当前类加载器。
回答by tannewt
Instead of using writeParcelable and readParcelable use writeToParcel and createFromParcel directly. So the better code is:
不使用 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();
}
回答by Amokrane Chentir
Just adding my 2 cents here, because I lost more than half a day scratching my head on this. You might get this error if you don't put the writes methods and reads methods in the exact same order. For instance the following would be wrong:
只是在这里加上我的 2 美分,因为我在这个问题上浪费了半天多的时间。如果您没有以完全相同的顺序放置 writes 方法和 read 方法,您可能会收到此错误。例如,以下内容是错误的:
@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();
}
By the way the author did this correctly but it might help someone one day.
顺便说一句,作者正确地做到了这一点,但有一天它可能会帮助某人。
回答by Camino2007
I got ClassNotFoundException too and posting my solution bc the answers here led me to the right direction. My scenario is that I have nested parcelable objects. Object A contains an ArrayList of Object's B. Both implement Parcelable. Writing the list of B Object's in class A:
我也得到了 ClassNotFoundException 并发布了我的解决方案 bc 这里的答案使我走向了正确的方向。我的情况是我嵌套了 Parcelable 对象。对象 A 包含对象 B 的 ArrayList。两者都实现 Parcelable。在 A 类中写入 B 对象的列表:
@Override
public void writeToParcel(Parcel dest, int flags) {
...
dest.writeList(getMyArrayList());
}
Reading the list in class A:
阅读A类中的列表:
public ObjectA(Parcel source) {
...
myArrayList= new ArrayList<B>();
source.readList(myArrayList, B.class.getClassLoader());
}
Thank you!
谢谢!
回答by shontauro
If you have an Object with a property of type of List objects you should pass the class loader when you read the property for example:
如果你有一个属性类型为 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];
}
};
}
Note: Is important that the class Outstanding implements the Parceable interface.
注意:Outstanding 类实现 Parceable 接口很重要。
回答by Ahmad Moussa
Well I had the same problem and solve it in a very silly way that I dont know if its called a solution at all.
好吧,我遇到了同样的问题,并以一种非常愚蠢的方式解决了它,我根本不知道它是否称为解决方案。
lets say you have this class you want to pass to another activity
假设您有这门课要传递给另一个活动
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 When I changed the:
就是这样当我改变了:
dest.writeString(name);
dest.writeInt(age);
to
到
dest.writeInt(age);
dest.writeString(name);
The problem was solved???!!!!
问题解决了???!!!
回答by Wirling
I got this exception because I was missing a constructor. The same must be done for all classes that implement Parcelable:
我得到这个异常是因为我缺少一个构造函数。所有实现 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];
}
};