Android中跨進程通訊傳遞Parcelable對象時出現android.os.BadParcelableException: ClassNotFoundException when unmarsh,dllnotfoundexception
轉載請註明出處:http://blog.csdn.net/bettarwang/article/details/45315091
按Google開發文檔的說法,在跨進程通訊時,推薦使用MessengerService而不是AIDL,所以最近在實現一個跨進程的Service時就採用了MessengerService的方法。
然後定義了這樣一個類:
public class BleServiceBean implements Parcelable { private String name; private String uuid; public BleServiceBean() { } public BleServiceBean(BluetoothGattService service) { uuid=service.getUuid().toString(); name= BleNamesResolver.resolveServiceName(uuid); } private BleServiceBean(Parcel in) { readFromParcel(in); } private void writeToParcel(Parcel out) { out.writeString(name); out.writeString(uuid); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out,int flags) { writeToParcel(out); } public void readFromParcel(Parcel in) { name=in.readString(); uuid=in.readString(); } public static final Parcelable.Creator<BleServiceBean>CREATOR=new Parcelable.Creator<BleServiceBean>(){ @Override public BleServiceBean createFromParcel(Parcel source) { return new BleServiceBean(source); } @Override public BleServiceBean[]newArray(int size) { return new BleServiceBean[size]; } };}在Service中擷取到相應資料後要傳遞給UI,有如下代碼:
Bundle bundle=new Bundle(); bundle.putParcelableArrayList(BleConnectUtils.BLE_SERVICE_BEAN_LIST,beanList); msg.setData(bundle); mClients.get(i).send(msg);
在Client端擷取資料的代碼如下:
ArrayList<BleServiceBean>beanList=bundle.getParcelableArrayList(BleConnectUtils.BLE_SERVICE_BEAN_LIST);
但是運行到此處時卻出現如下錯誤:
FATAL EXCEPTION: main
Process: com.example.xxx.xx, PID: 1203
android.os.BadParcelableException: ClassNotFoundException when unmarshalling:
給出的出錯原因如下:
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.xxx.xxx.bean.BleServiceBean" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /data/cust/lib, /system/lib]]
後面才發現原來是Android有兩種不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎麼載入android classes,apk classloader知道怎麼載入你的代碼,即可以知道你自訂的類,apk classloader繼承自framework classloader,所以也知道怎麼載入android classes。在應用剛啟動時,預設class loader是apk classloader,但在系統記憶體不足應用被系統回收會再次啟動,這個預設class loader會變為framework classloader了,所以對於自己的類會報ClassNotFoundException。
如果是在要傳遞的JavaBean中有其中一個Field繼承自Parcelable,那麼有很簡單的處理方法,只要把類似rect = in.readParcelable(null);改為config = in.readParcelable(Rect.class.getClassLoader());
但是我們這裡是直接傳遞一個List<BleServiceBean>,那要怎麼辦呢?
其實很簡單,只需要在Client端讀取Bundle中的資料之前加上如下一行代碼:
bundle.setClassLoader(getClass().getClassLoader());
這樣就會使用apk classloader載入。