本文主要分析android.os.badparcelableexception: classnotfoundexception when unmarshalling这个异常的原因及解决方法,解释了android的class loader.
一、现象:
应用打开,home键到后台,过一段时间打开,偶现fc,log如下:
1
2
3
e/androidruntime(9085): caused by: android.os.badparcelableexception: classnotfoundexception when unmarshalling: *.*.*.*.layout$config
e/androidruntime(9085): at android.os.parcel.readparcelable(parcel.java:2077)
e/androidruntime(9085): at *.*.*.<init>(layout.java:105)
程序中的写法是
java
4
5
6
7
public config config;
public rowview(parcel in){
type = in.readstring();
interfaceurl = in.readstring();
size = in.readint();
config = in.readparcelable(null);
}
报错的语句即为config = in.readparcelable(null);
二、原因分析:
根据android文档介绍:
readparcelable (classloader loader)
loader a classloader from which to instantiate the parcelable object, or null for the default class loader.
即loader为空时系统会采取默认的class loader。
android有两种不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎么加载android classes,apk classloader知道怎么加载you code,apk classloader继承自framework classloader,所以也知道怎么加载android classes。
在应用刚启动时,默认class loader是apk classloader,但在系统内存不足应用被系统回收会再次启动,这个默认class loader会变为framework classloader了,所以对于自己的类会报classnotfoundexception。
三、解决方法:
将config = in.readparcelable(null);改为config = in.readparcelable(config.class.getclassloader());
config.class.getclassloader()即为apk classloader, 其中config.class可以改为你程序中自己写的任意类,因为他们同样指向apk loader
嘿嘿,试着改为config = in.readparcelable(activity.class.getclassloader());你会发现依然classnotfoundexception因为activity.class.getclassloader()指向的是framework classloader
四、如何测试重现这个问题,方便测试呢:
重现这个问题即使的应用被系统回收,把设置->开发者选项->不保留活动开关打开,打开测试程序按home键,再打开测试程序就会执行到这句。
如果你是在onsaveinstancestate中保存
savedinstancestate.putparcelable(key, value),则需要设置bundle的class loader,如下:
savedinstancestate.setclassloader(getclass().getclassloader());
ps:
(1)、readparcelablearray(classloader loader), readparcelable, readarray,readarraylist, readbundle, readhashmap, readparcelable, readsparsearray, readvalue, readlist, readmap也有可能报上面的异常