Android:一个Multidex引发的VerifyError和Class Not Found问题
2016-03-24 19:20
387 查看
一个困扰两天的问题终于解决了,下面记录一下该问题解决的历程,希望能对那些遇到类似问题的猿们有些帮助。
当把编译好的jar包放入应用中,且应用编译通过,运行时报各种问题:
等等……
网上说的各种解决办法都试过了也没用。后来看到一个帖子
http://www.cnblogs.com/successjerry/p/4402962.html
说java.lang.VerifyError的解决办法,说是proguard引起的。但是我编译的是debug版本,根本没有用proguard啊!但实在没办法了,我就想编个release版本看看我的proguard有没有问题。结果一试上面的两个报错都没有了,但是出现 了另外一个class找不到的现象,是一个匿名内部类找不到。
其实这个时候应该可以想到的是可能是proguard去除了无用的方法,导致应用的方法数在65535之内,前面的出问题的几个类回到了主包,因此前面出现的两个问题就没有了。
但是但是只考虑是progurad混淆引起的,通过反编译apk也确实发现匿名内部类创建是变成了new 1(this)之类的,但是主要解决方向都在这里。
后来纠结了两天,当中也请教了好多人,还是没有解决。当时想着就先放一放,就把这个出错的地方注释掉了,应用可以跑起来了。
后来的一个线索的出现是,当时修改了一下jar包,往里面添加了几个方法,运行应用的时候又出现类找不到,方法找不到,这是就恍然大悟了,可能是方法超限的问题导致的。
后来看了一下应用的设置,在build.gradle里面确实配置了分包:
/article/1875745.html
可能需要在Application类的attachBaseContext方法中加上:
一试,果然没有报错了。
在
http://weibo.com/p/1001603884849646685222
和
/article/2530552.html
中有介绍:
使用了Multidex的APK运行在Android5.0之前的设备上时,还需要配合support库里面的MultiDex.install接口才行。有三种方法使用MultiDex.install接口:
如果没有自定义自己的Application,那么在AndroidManifest.xml将APK的Application指定为MultiDexApplication。
如果自定义了自己的Application,那么将自己的Application继承于MultiDexApplication。
如果不想继承于MultiDexApplication,那么重写父类Applicatio的成员函数attachBaseContext,并且在该成员函数中调用MultiDex.install接口。
这里我们采用方法3。
最后,使用了Multidex的APK运行在Android5.0之后的设备上时,不需要MultiDex.install支持。这是因为Android 5.0使用的是ART虚拟机,ART虚拟机解决了Dalvik虚拟机方法数限制在65K的问题。Android 5.0在安装一个使用了MultiDex的APK时,会收集它的Main Dex和Additional Dex,然后将它们翻译成Native Code,最终保存在一个OAT文件中。因此就不需要MultiDex.install了。
MultiDex.install干了什么事情呢?它首先是收集APK里面的Additional Dex,并且找到APK所使用的PathClassLoader。接下来通过反射得到PathClassLoader的成员变量pathList,这是一个类型为DexPathList的对象。DexPathList里面又有一个成员变量dexElements,指向的是一个Element数组,该数组包含了系统主动为APK加载的Dex。再接下来,又通过反射调用上述的DexPathList对象的成员函数makeDexElements加载前面找到的Additional Dex,并且将这些Additional Dex增加到它的成员变量dexElements描述的Element数组中。
Dalvik虚拟机在查找一个Class的时候,会询问APK使用的PathClassLoader。PathClassLoader又询问它的成员变量pathList指向的DexPathList对象。DexPathList又询问保存在它的成员变量dexElements描述的一个Element数组中的Dex。因此,就可以想象中,一旦MultiDex.install调用过后,APK就可以正常使用打包在AdditionalDex中的Class。
希望对大家有所帮助。
问题背景
由于项目要适配android4.X,而应用需要引用的一个jar包的4.X版本就只能用JDK1.6来编译,而应用要用JDK1.7来编译,这个情况也为该问题的解决带来了干扰。当把编译好的jar包放入应用中,且应用编译通过,运行时报各种问题:
java.lang.VerifyError java.lang.NoClassDefFoundError
等等……
网上说的各种解决办法都试过了也没用。后来看到一个帖子
http://www.cnblogs.com/successjerry/p/4402962.html
说java.lang.VerifyError的解决办法,说是proguard引起的。但是我编译的是debug版本,根本没有用proguard啊!但实在没办法了,我就想编个release版本看看我的proguard有没有问题。结果一试上面的两个报错都没有了,但是出现 了另外一个class找不到的现象,是一个匿名内部类找不到。
其实这个时候应该可以想到的是可能是proguard去除了无用的方法,导致应用的方法数在65535之内,前面的出问题的几个类回到了主包,因此前面出现的两个问题就没有了。
但是但是只考虑是progurad混淆引起的,通过反编译apk也确实发现匿名内部类创建是变成了new 1(this)之类的,但是主要解决方向都在这里。
后来纠结了两天,当中也请教了好多人,还是没有解决。当时想着就先放一放,就把这个出错的地方注释掉了,应用可以跑起来了。
后来的一个线索的出现是,当时修改了一下jar包,往里面添加了几个方法,运行应用的时候又出现类找不到,方法找不到,这是就恍然大悟了,可能是方法超限的问题导致的。
后来看了一下应用的设置,在build.gradle里面确实配置了分包:
multiDexEnabled true
解决办法
后来在网上查资料,发现/article/1875745.html
可能需要在Application类的attachBaseContext方法中加上:
android.support.multidex.MultiDex.install(this);
一试,果然没有报错了。
在
http://weibo.com/p/1001603884849646685222
和
/article/2530552.html
中有介绍:
使用了Multidex的APK运行在Android5.0之前的设备上时,还需要配合support库里面的MultiDex.install接口才行。有三种方法使用MultiDex.install接口:
如果没有自定义自己的Application,那么在AndroidManifest.xml将APK的Application指定为MultiDexApplication。
如果自定义了自己的Application,那么将自己的Application继承于MultiDexApplication。
如果不想继承于MultiDexApplication,那么重写父类Applicatio的成员函数attachBaseContext,并且在该成员函数中调用MultiDex.install接口。
这里我们采用方法3。
最后,使用了Multidex的APK运行在Android5.0之后的设备上时,不需要MultiDex.install支持。这是因为Android 5.0使用的是ART虚拟机,ART虚拟机解决了Dalvik虚拟机方法数限制在65K的问题。Android 5.0在安装一个使用了MultiDex的APK时,会收集它的Main Dex和Additional Dex,然后将它们翻译成Native Code,最终保存在一个OAT文件中。因此就不需要MultiDex.install了。
MultiDex.install干了什么事情呢?它首先是收集APK里面的Additional Dex,并且找到APK所使用的PathClassLoader。接下来通过反射得到PathClassLoader的成员变量pathList,这是一个类型为DexPathList的对象。DexPathList里面又有一个成员变量dexElements,指向的是一个Element数组,该数组包含了系统主动为APK加载的Dex。再接下来,又通过反射调用上述的DexPathList对象的成员函数makeDexElements加载前面找到的Additional Dex,并且将这些Additional Dex增加到它的成员变量dexElements描述的Element数组中。
Dalvik虚拟机在查找一个Class的时候,会询问APK使用的PathClassLoader。PathClassLoader又询问它的成员变量pathList指向的DexPathList对象。DexPathList又询问保存在它的成员变量dexElements描述的一个Element数组中的Dex。因此,就可以想象中,一旦MultiDex.install调用过后,APK就可以正常使用打包在AdditionalDex中的Class。
总结
其实在当发生Debug报错而Release版本有些报错就没有的时候,本来就可以往这方法考虑的,但是当时走错了方向,一直以为是混淆导致的问题,没有考虑到minifyEnabled true这个配置在release中也生效了。希望对大家有所帮助。
相关文章推荐
- Android之 如何在退出一个activity后,很好的取消AsyncTask继续运行
- android 按钮变化颜色
- Android官方开发文档Training系列课程中文版:管理Activity的生命周期之启动一个Activity
- Android中为控件之间添加分割线
- android常用颜色配置xml
- android studio 获取sha1 和 md5 的值
- Android studio如何集成ShareSDK详解
- Android数据库 之 SQLite数据库
- eclispe快捷键
- as快捷键
- android学习之蓝牙 - 蓝牙连接打印机Demo
- android依赖库(依赖工程)导入
- android Music 中如何添加设置双卡铃声的菜单
- android中fragment与activity之间通信原理以及例子
- 按下更新按钮,每隔1S自动更新进度条,更新到100%自动消失
- [Android] AndroidManifest.xml出现问题
- 进入应用动画闪屏, android5.0初始动画,不执行解决等方案总结
- Android - MyFragment.java
- Android版本和API Level对应关系
- Android HAL的STUB的具体处理