Parcel: Class not found when unmarshalling: 自定义类

问题描述

如标题,这个问题网上有很人遇到,场景是跨进程启动activity或service通传Intent传Parcel数据时遇到,网上总结是类加载器设置不对的原因。我遇到的问题场景是在当前进程中,启动新的activity解析传过来的Parcel子类时出现的异常,异常backtrace如下:

 Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.myapplication.UserBean
        at android.os.Parcel.readParcelableCreator(Parcel.java:2554)
        at android.os.Parcel.readParcelable(Parcel.java:2480)
        at android.os.Parcel.readValue(Parcel.java:2383)
        at android.os.Parcel.readMapInternal(Parcel.java:2733)
        at android.os.Parcel.readHashMap(Parcel.java:1871)
        at com.example.myapplication.TestBean.<init>(TestBean.java:19)
        at com.example.myapplication.TestBean$1.createFromParcel(TestBean.java:36)
        at com.example.myapplication.TestBean$1.createFromParcel(TestBean.java:33)
        at android.os.Parcel.readParcelable(Parcel.java:2489)
        at android.os.Parcel.readValue(Parcel.java:2383)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2750)
        at android.os.BaseBundle.unparcel(BaseBundle.java:269)
        at android.os.Bundle.getParcelable(Bundle.java:864)
        at android.content.Intent.getParcelableExtra(Intent.java:6464)
        at com.example.myapplication.TestActivity.onStart(TestActivity.java:25)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1249)
        at android.app.Activity.performStart(Activity.java:6830)

问题分析

顺藤摸瓜,使用when unmarshalling关键字去看下Parcel.java的源码
在这里插入图片描述
然后,设置一下断点,去看下loader是什么,以及什么时候传进入来的(tips:这里时候要用方法断点,源码行号断点是断不下的呀)
在这里插入图片描述
问题的代码是:

public class TestBean implements Parcelable {
    private String tag;
    private HashMap<String, Object> mHashMap;

    public TestBean(String tag) {
        this.tag = tag;
        mHashMap = new HashMap<>();
    }

    protected TestBean(Parcel in) {
        tag = in.readString();
        mHashMap = in.readHashMap(HashMap.class.getClassLoader());//这里传入了Loader有问题!!!
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(tag);
        dest.writeMap(mHashMap);
    }

    @Override
    public int describeContents() {
        return 0;
    }

解决方案

手动更改类加载器为PathClassLoader

		mHashMap = in.readHashMap(HashMap.class.getClassLoader())
		# 修改如下
        mHashMap = in.readHashMap(TestBean.class.getClassLoader());

我们可以调试看下TestBean.clas.getClassLoader是什么Loader,如下图所示:
在这里插入图片描述

经验总结

  • 在Parcel对象中使用HashMap时,反序列化的时候,设置的类加载器必须是应用类加载器(dalvik.system.PathClassLoader),不要使用
  • Android Studio的Parcel自动代码生成,对于HashMap的读取/反系统化默认是设置了启动器加载器(HashMap.class.getClassLoader()),需要手机改成应用类加载器(自定义类.class.getClassLoader)
  • Android中BootClassLoader是用于加载framework中的类,PathClassLoader是用于加载apk的dex中的类,即我们自己定义的类
  • 在Parcel中使用HashMap,且HashMap存放类是没有问题的,注意Loader的配置就行了

参考文档

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值