Android NoClassDefFoundError 之 PersistableBundle

今天测试反馈,在应用在华为麦芒上出现了闪退,找了台类似的低端机,复现了问题

E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: android/os/PersistableBundle
at java.lang.Class.getDeclaredMethods(Native Method)
at java.lang.Class.getPublicMethodsRecursive(Class.java:955)
at java.lang.Class.getMethods(Class.java:938)
at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingReflectionInSingleClass(SubscriberMethodFinder.java:157)
at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingInfo(SubscriberMethodFinder.java:88)
at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:64)
at org.greenrobot.eventbus.EventBus.register(EventBus.java:136)
at com.mx.engine.event.EventProxy.register(EventProxy.java:44)
at com.mx.framework2.view.ui.BaseActivity.init(BaseActivity.java:139)
at com.mx.framework2.view.ui.BaseActivity.onCreate(BaseActivity.java:130)
at com.gome.common.base.GBaseActivity.onCreate(GBaseActivity.kt:27)
at android.app.Activity.performCreate(Activity.java:5043)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2033)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2094)
at android.app.ActivityThread.access$600(ActivityThread.java:134)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1202)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4777)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:764)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:531)
at dalvik.system.NativeStart.main(Native Method)

在错误信息中,出现了EventBus的身影,因此直奔github eventbus,在issues搜索PersistableBundle关键词,找到了网友提交的类似情形 https://github.com/greenrobot/EventBus/issues/156
官方解释了该问题出现的原因(http://greenrobot.org/eventbus/documentation/faq/)

class PersistableBundle was added in API level 21. Along with the new class some new life cycle methods were introduced in the class Activity having PersistableBundle as a parameter, for example onCreate (Bundle savedInstanceState, PersistableBundle persistentState). Now, if you override this method and you try to register this Activity to EventBus on a older device, we have exactly the scenario described to cause to bug. Understanding why this happens will help to resolve the issue easilyclass PersistableBundle was added in API level 21. Along with the new class some new life cycle methods were introduced in the class Activity having PersistableBundle as a parameter, for example [onCreate (Bundle savedInstanceState, PersistableBundle persistentState)](http://developer.android.com/intl/in/reference/android/app/Activity.html#onCreate(android.os.Bundle, android.os.PersistableBundle)). Now, if you override this method and you try to register this Activity to EventBus on a older device, we have exactly the scenario described to cause to bug. Understanding why this happens will help to resolve the issue easily

在android5.0中引入了PersistableBundle,在Activity的一些生命周期的方法中,增加了PersistableBundle类型形参,比如

protected void onCreate(@Nullable Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
}

public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
      onCreate(savedInstanceState);
}

protected void onRestoreInstanceState(Bundle savedInstanceState) {
      if (mWindow != null) {
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
                   mWindow.restoreHierarchyState(windowState);
            }
      }
 }

public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
      if (savedInstanceState != null) {
             onRestoreInstanceState(savedInstanceState);
      }
 }

对比可以发现,相同名称的生命周期方法,带PersistableBundle的方法修饰符为public,而我们常重载的为protected。EventBus通过反射来获取注册类所有的订阅方法,考虑到效率问题,会调用Class.getDeclaredMethods(),也是就public方法,如果重载了含有PersistableBundle的方法,EventBus在类初始化的时候会访问该方法,在系统版本低于Android5.0的手机上,就会因为找不到PersistableBundle.class而抛出异常
仔细检查了项目代码,果然重载了父类的带PersistableBundle的生命周期方法,去掉PersistableBundle,crash消失了

Android NoClassDefFoundError 之 PersistableBundle_第1张图片
EventBus register方法代码片段

Android NoClassDefFoundError 之 PersistableBundle_第2张图片
修改之前代码

Android NoClassDefFoundError 之 PersistableBundle_第3张图片
修改之后代码

你可能感兴趣的