ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState 问题分析

疑难问题:android.os.BadParcelableException

ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState 问题分析

问题描述

-----------------------Crash 1 Message-----------------------
完整log: logcat.txt
02-20 21:08:32.727 E/AndroidRuntime(32306): FATAL EXCEPTION: main
02-20 21:08:32.727 E/AndroidRuntime(32306): Process: com.mt.mtxx.mtxx, PID: 32306
02-20 21:08:32.727 E/AndroidRuntime(32306): android.os.BadParcelableException: ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.Parcel.readParcelableCreator(Parcel.java:3042)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.Parcel.readParcelable(Parcel.java:2964)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.Parcel.readValue(Parcel.java:2866)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.Parcel.readArrayMapInternal(Parcel.java:3244)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.BaseBundle.unparcel(BaseBundle.java:236)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.BaseBundle.size(BaseBundle.java:355)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.app.servertransaction.LaunchActivityItem.hashCode(LaunchActivityItem.java:208)
02-20 21:08:32.727 E/AndroidRuntime(32306): at java.util.AbstractList.hashCode(AbstractList.java:541)
02-20 21:08:32.727 E/AndroidRuntime(32306): at java.util.Objects.hashCode(Objects.java:98)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.app.servertransaction.ClientTransaction.hashCode(ClientTransaction.java:241)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.app.servertransaction.TransactionExecutorHelper.tId(TransactionExecutorHelper.java:266)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:86)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.Handler.dispatchMessage(Handler.java:107)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.os.Looper.loop(Looper.java:214)
02-20 21:08:32.727 E/AndroidRuntime(32306): at android.app.ActivityThread.main(ActivityThread.java:7356)
02-20 21:08:32.727 E/AndroidRuntime(32306): at java.lang.reflect.Method.invoke(Native Method)
02-20 21:08:32.727 E/AndroidRuntime(32306): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
02-20 21:08:32.727 E/AndroidRuntime(32306): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

这个异常来自于Bugly。从去年6月的8820版本就开始存在。 日崩溃量差不多在150左右,是个历史疑难问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O2Xyrtx5-1616553788110)(http://jira.meitu.com/secure/attachment/353350/screenshot-1.png)]

从Bugly的出错堆栈,跟踪数据,跟踪日志等维度上都没有找到有用的信息。只知道奔溃发生在主线程,而且App的使用时长 1-3s。也就是说通常是
Application一启动就崩溃了,还没有进入到Activity的页面初始化。

通过Google分析了下这个问题:

  1. 该异常表示对Parcelable数据进行反序列化时找不到相关类。

2.这种报错有一种原因是与Android的classloader机制有关。Android有两种不同的classloaders:framework classloader和Apk classloader,应用启动时默认的classloader是Apk classloader,可以加载Parcelable反序列化所需的类。当内存不足时,默认classloader将变为framework classloader,它不知道如何加载自己定义的类,因而会报错。

通常的解决方法是:在解组数据前,加上bundle.setClassLoader(getClass().getClassLoader()),将恢复Apk classloader方式。

但是这个异常的Parcelable 数据是在FragmentManagerState里面序列化的,这个数据里面保存的是Activity页面中的Fragment数据, 这个数据并不是我们手动序列化,而是App退到后台的时候,使用onSaveInstanceState 自动帮我们序列化的。是系统的行为。

序列化的时机是:android.app.Activity#onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle)
反序列化的时机是:是android.app.Activity#onCreate(android.os.Bundle)

因此可以大概推测出这个问题的发生路径:

  1. APP切换到后台,当进入后台比较久或者内存不够的时候,APP被杀死。

  2. 再次切换APP到前台,这时候安卓系统会根据 杀死APP 的时候 onSaveInstanceState 方法中保存的Fragment信息,重构页面。但是这时候 使用的是Framework classLoader, 会找不到这个Fragment,导致无法Activity无法构建成功,导致崩溃。

更深入分析发现,这异常只会发生在 Android 10 的版本,而且 Android 官方Issue那边有条相关的反馈

issue的 状态的 wont fix。 官方的回复是这个问题 只会发生在 Android 10 预览版。 安卓10 已经修复了这个问题,建议厂商升级软件版本

解决

问题已经比较清晰了,那么就可以尝试解决了。 由于这个异常是发生在Activity#onCreate 中,因此,我们需要在 Activity基类中拦截这个异常,同时为了减少对其他版本和手机的影响,限制了系统版本并缩小了机型范围。

    //Top5易发生的机器
    private val deviceModel = arrayOf("REDMI 8A", "V1962A", "V1986A", "PDPM00", "V1938CT")

   private fun condition(): Boolean {
        val deviceMode = DeviceUtils.getDeviceMode()
		//只处理安卓10机器
        val versionEqual = Build.VERSION.SDK_INT == Build.VERSION_CODES.Q
        return versionEqual && deviceModel.contains(deviceMode)
    }

    fun intercept(context: Context, bundle: Bundle?) {
        if (bundle != null && condition()) {
            bundle.classLoader = context.classLoader
        }
    }
	//GlideMemoryOptimizeActivity Activity基类中
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        FixFragmentHelper.INSTANCE.intercept(this,savedInstanceState);
        super.onCreate(savedInstanceState);
   		...
    }
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值