本文主要分析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也有可能報上面的異常