64k的各种异常
当你的应用程序和库引用达到一定规模,你遇到构建错误显示你的应用已经达到了一个Android应用程序构建体系结构的限制。早期版本的构建系统报告这个错误如下:
1.ConversiontoDalvik format failed:
2.Unabletoexecute dex:methodIDnotin[0, 0xffff]:65536
或者
UNEXPECTED TOP-LEVEL EXCEPTION:java.lang.IllegalArgumentException:method ID notin[0,0xffff]:65536atcom.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501) atcom.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282) atcom.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490) atcom.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167) atcom.android.dx.merge.DexMerger.merge(DexMerger.java:188) atcom.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439) atcom.android.dx.command.dexer.Main.runMonoDex(Main.java:287) atcom.android.dx.command.dexer.Main.run(Main.java:230) atcom.android.dx.command.dexer.Main.main(Main.java:199) atcom.android.dx.command.Main.main(Main.java:103)
最新版本的Android构建系统显示一个不同的错误,但是是同样一个问题:
1.trouble writing output:
2.Too many field references:131000;maxis65536.
3.You maytryusing--multi-dex option.
或者
1.Error:The numberofmethodreferencesina.dexfilecannotexceed64K.
上面的错误显示一个共同的数字:65536。这个数字是重要的,它代表了引用的总数,可以在单个调用的代码Dalvik可执行(Dex)字节码文件。如果你的Android应用发生这个错误,恭喜你,你的代码已经达到了一定的量!本文解释了如何解决这个限制并继续构建应用程序。
关于64 k引用限制
Android应用程序(APK)在Dalvik可执行文件的形式包含可执行的字节码文件(DEX)文件,其中包含已编译的代码来运行你的应用程序。Dalvik可执行规格限制一个Dex文件包含65536个方法:包括Android框架方法、Library方法的总数、和你自己的代码方法总数。因为65536等于64×1024,这一限制被称为“64k引用限制”。
这个极限就要求我们配置应用程序的构建过程,需要生成多个DEX文件,所以称为multidex 配置。
分析原因与注意事项
解决方法分Android 5.0及以上系统和5.0以下系统怎么做。客官们不要着急,先看我一个个分析原因,毕竟我要装下逼哈哈。
Android 5.0(API leve 21)之前的系统使用Dalvik执行应用程序代码。默认情况下,Dalvik限制一个apk只有一个Dex文件。为了绕过这个限制, 我们可以使用multidex support library,它成为我们APK的主要DEX文件的一部分,负责管理我们APK访问其他DEX文件和代码。
注意: 如果咱的项目minSdkVersion是20或更低,运行到Android 4.4(API leve 20)或者更低版本的设备上时需要禁用AndroidStudio的即时运行
Android 5.0(API leve 21)和更高的系统使用runtime是ART ,原生支持从应用的apk文件加载多个DEX文件。ART在安装应用时预编译应用程序,会扫描多个classes(..N).dex文件编译成一个.oat的文件。更多Android5.0 runtime的更多信息,请参见即时运行-instant-run。
注意: 如果你使用即时运行, AndroidStudio自动配置你的应用程序,你应用程序的minSdkVersion应该设置为21或更高。因为即时只工作在你APP的Debug版本,你任然需要配置你的release版本构建时用multidex避免64k的限制。
在配置我们的App启用64k或者更多方法引用之前,我们可以减少应用代码内的调度总数,包括我们自身应用的方法和第三方的库,下面的几个策略或许可以帮到你:
检查你的APP的直接和间接的过度依赖关系:有时候我们用到某个Libaray的某几个方法或者功能时这个库非常大,减少这种依赖可能对与避免64k的问题非常有效。
在正式打包构建的时候,使用代码混淆器ProGuard混淆移除未使用的代码,也就是不把没有使用的代码打包到我们的apk中。
使用上面的方法可以帮助我们避免在应用程序中生成太多无用的方法和减小我们apk的大小,这对于用自己服务器做app更新升级的同学是非常有帮助的。
这里给大家推荐下任玉刚同学的插件式开发框架:https://github.com/singwhatiwanna/dynamic-load-apk,共同参与开发者:田啸,宋思宇。
在Android SDK Build Tools 21.1或者更高版本的build工具中用Android plugin gradle。确保你更新Android SDK build tools和Android support到最新版本,然后用multidex配置应用程序。我们必须要做两步。
在gradle中依赖multidex,并启用multiDexEnable:
android {
compileSdkVersion21
buildToolsVersion
defaultConfig {
...
minSdkVersion14
targetSdkVersion21
...
// Enabling multidex support.
multiDexEnabled true //加上这一句
}
}
dependencies {
compile'com.android.support:multidex:1.0.1' ////加上这一句
}
第二步,继承android.support.multidex.MultiDexApplication类
第一种情况,如果我们的APP没有重写过Application类,我们直接继承MultiDexApplication,然后在manifest.xml中注册Application即可。
第二种情况,如果我们已经重写过Application类,重写attachBaseContext(Context)方法,并调用MultiDex.install(this);即可:
protectedvoidattachBaseContext(Context base)
{
super.attachBaseContext(base);
MultiDex.install(this);
}
}
因为我翻过MultiDexApplication的源码了,里面就是重写了这个方法而已哈哈:
publicclassMultiDexApplicationextendsApplication{publicMultiDexApplication() { }protectedvoidattachBaseContext(Context base)
{super.attachBaseContext(base);
MultiDex.install(this);
}
}
//来源于AndroidStudio利用android-support-multidex解决65536问题64k问题