诡异的NoClassDefFoundError错误——也可能是65536引起的

诡异的NoClassDefFoundError错误

一 场景

症状一

本来好好的App,在引入了某个第三方库之后,忽然就开始报错了:

Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.yourapp.XXX”

ClassNotFoundException——这是个很常见的错误啊,加载某些类的时候没找到嘛!
然而这次的诡异之处在于,这个com.yourapp.XXX明明就在那里,Android系统你为啥找不到呢,难道见鬼了么。

症状二

经过测试发现,只有Android2.x、Android4.x的机型会出现这种情况,Android5.x/6.x则能顺利通过

二 原因呢

如果你经过反复的Clean Project、 Rebuild Project、把某个包冲删除重新加入、重新安装app…… 还是没有找到原因的话,那很有可能就是因为那个著名的the 64K Reference Limit问题了。

名词解释: Android application (APK) files contain executable bytecode files in the form of Dalvik Executable (DEX) files, which contain the compiled code used to run your app. The Dalvik Executable specification limits the total number of methods that can be referenced within a single DEX file to 65,536—including Android framework methods, library methods, and methods in your own code. In the context of computer science, the term Kilo, K, denotes 1024 (or 2^10). Because 65,536 is equal to 64 X 1024, this limit is referred to as the ’64K reference limit

用中国话说:就是在Android中,由于某些原因,会导致单个Dex文件中最多只能容纳65536(64k)个方法,如果app中的方法数量多于65536个,就会导致这种错误。

千万不要觉得65536很多啊

一般在项目中,我们自己收写的代码只是很小一部分,大部分代码是在你引用的第三方轮子中啊,比如这些最常用的:

Name | Method Count ——— | ————- Gson 2.3 | 1,243 Jackson 3.4.3 | 6,731 Android Support V4 21 | 8,078
所以如果用的轮子多了,分分钟就会到了64k大限了。

这个问题有时会有其他的日志:

Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

或者:

Too many field references: 131000; max is 65536. You may try using –multi-dex option.

如果是这两个报错,问题就明显多了,一看到65536这个神奇的数字就可以定位到这个病因了。

三 解决方案

知道病因之后,治病就简单了

精简代码,去除冗余

  • 经常清理一些过期不要的代码是个好习惯
  • 如果有功能类似的轮子也可以只保留一个,比如Gson/Jackson、Fresco/Glide、EventBus/Otto

开启ProGuard

自动去除一些未使用的代码,不过要注意很多轮子中的ProGuard配置,不然可能会导致动态加载的一些方法失效

终极方案MultiDex

名词解释:MultiDex allows you to use multiple DEX files contained within one APK. With a few steps, your classes will split automatically into several DEX files (classes.dex, classes2.dex, classes3.dex, etc) in case you reach the method index limit. Information on how to integrate MultiDex into your application will follow.

用中国话说,MultiDex就是一项技术,可以让一个apk中包含多个dex文件,每个dex文件中都不超过64k个方法,这样就OK啦

开启MultiDex方法

如果Android 5.0(API 21)以上会自动支持MultiDex,当然目前(2016年)我们的app可能不能只支持到API21了,所以还是需要在项目中配置的,需要如下三步:

1 在build.grade中配置defaultConfig:

defaultConfig {
...
// Enabling multidex support.
multiDexEnabled true
}

2 在build.grade中配置dependencies:

dependencies {
compile 'com.android.support:multidex:1.0.0'
}

3 使用MultiDexApplication取代Application:

① 如果没有自定义Application,那么在AndroidManifest.xml中指定MultiDexApplication即可
② 如果有自定义的MyApplaction extends Application,那么改成MyApplaction extends MultiDexApplication
③ 如果有自定义的MyApplaction继承了一个不能修改的XApplication,那么覆盖attachBaseContext()方法,在其中调用一下MultiDex.install(this)也可以。

四 链接

ProGuard: https://developer.android.com/studio/build/shrink-code.html
Multidex官方指南: https://developer.android.com/studio/build/multidex.html

ps:WordPress的MD插件不大好,文章格式有些乱,懒得校正了,就这样吧。


以上。
本文链接:http://www.barryzhang.com/archives/435

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*