I\'ve got a few classes that implement Parcelable and some of these classes contain each other as properties. I\'m marshalling the classes into a Parcel to pass them between
I got this exception because I was missing a constructor. The same must be done for all classes that implement 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];
}
};
I had the same problem with the following setup: some handler creates a Message and sends its over a Messenger to a remote service.
the Message contains a Bundle where I put my Parcelable descendant:
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.
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:
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.
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.
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.