Android Parcelable反序列化报错笔记:java.lang.RuntimeException: Unmarshalling unknown type code at offset(代码片
Posted xiong_it
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Parcelable反序列化报错笔记:java.lang.RuntimeException: Unmarshalling unknown type code at offset(代码片相关的知识,希望对你有一定的参考价值。
事件背景
有个实体类,利用Parcelable序列化保存在了本地,在新版本上新增了一个字段后,反序列化取数据时,报错如下:
java.lang.RuntimeException: Parcel android.os.Parcel: Unmarshalling
unknown type code xx at offset xx
代码示意
// 旧版本数据结构
public class ParcelableObject implements Parcelable {
private int i;
private float f;
public ParcelableObject() {
}
// getter & setter
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.i);
dest.writeFloat(this.f)
}
protected ParcelableObject(Parcel in) {
this.i = in.readInt();
this.f = in.readFloat();
}
public static final Creator<ParcelableObject> CREATOR = new Creator<ParcelableObject>() {
@Override
public ParcelableObject createFromParcel(Parcel source) {
return new ParcelableObject(source);
}
@Override
public ParcelableObject[] newArray(int size) {
return new ParcelableObject[size];
}
};
}
新版代码增加了一个newVar字段,同时按顺序加上了读写方法。
// 新的数据结构:同样代码做省略处理
public class ParcelableObject implements Parcelable {
private int i;
private float f;
// 新增字段
private int newVar;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.i);
dest.writeFloat(this.f);
dest.writeInt(newVar);
}
protected ParcelableObject(Parcel in) {
this.i = in.readInt();
this.f = in.readFloat();
try {
// 防止旧版数据报错。
this.newVar = in.readInt();
} catch(Exception e) {
// 报错时的兜底默认值
this.newVar = defautltValue;
// 报错不在这里,上面渠道newVar数据!!!!!!!!!
}
}
}
即使如上所示,添加了保护代码,可以依然报错:
java.lang.RuntimeException: Parcel android.os.Parcel: Unmarshalling unknown type code xx at offset xx
报错原理
序列化数据是一段连续的内存地址,会按照每个数据所占的大小去内存中取值,newVar取到下一段内存中的int值,可是每次取值都会根据该数据类型的所占位数产生一次偏移,所以导致整体数据去不全,最后报错。
解决办法
将newVar用对象类包装,取值失败,进入异常捕获,会进入默认的兜底默认值赋值,并且重设偏移量回到原偏移量
// 新的数据结构:同样代码做省略处理
public class ParcelableObject implements Parcelable {
private int i;
private float f;
// 新增字段利用对象包装
private NewVarObj newVarWrapper;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.i);
dest.writeFloat(this.f);
dest.writeSerializable(newVarWrapper);
}
protected ParcelableObject(Parcel in) {
this.i = in.readInt();
this.f = in.readFloat();
// 记录当前偏移量
int positionOffset = in.dataPosition();
try {
// 防止旧版数据报错。因为是取对象值,无法取到,进入异常捕获流程,进行默认赋值
this.newVar = (NewVarObj) in.readSerializable();
} catch(Exception e) {
// 报错时的兜底默认值
this.newVar = defautltValue;
// 将偏移量重设回去!!!!!!!!!
in.setDataPosition(positionOffset);
}
}
}
// 新字段包装类型
public class NewVarObj implements Serializable {
private static final long serialVersionUID = -934758980857565111L;
private int newVar;
// getter & setter
}
以上是关于Android Parcelable反序列化报错笔记:java.lang.RuntimeException: Unmarshalling unknown type code at offset(代码片的主要内容,如果未能解决你的问题,请参考以下文章