0. 前言
因为单个DEX文件能够包含的最大方法总数为65536,通常APK包含一个DEX文件,因此Android应用的方法总数不能超过这个数量,这包括Android框架、第三方类库和你自己开发的代码。随着第三方类库的加入,方法数就会迅速膨胀。直到遇见下面这个错误:
com.android.dex.DexIndexOverFlowException: method ID not in [0, 0xffff]: 65536
带着这个问题开始这篇文章,转载请注明出处:Android开发——解决方法数越界问题_SEU_Calvin的博客-CSDN博客
1. 引入multidex
2014年Google正式提出multidex为解决此问题的官方方案,即使用Gradle构建多DEX应用。Android 5.0之前需要引入extras/android/support/multidex/library/libs/android-support-multidex.jar, 5.0以后默认支持了multidex,所以在Bulid Tool21.1以及以上版本配置multidex是一件容易的事情。
1.1 修改Gradle配置文件
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support
multiDexEnabled true
}
...
}
并在dependencies中添加multidex的依赖:
dependencies {
...
compile 'com.android.support:multidex:1.0.0'
}
1.2 在代码中加入支持multidex的功能
根据MultiDexApplication JavaDoc的建议,共有三种可选方法:
(1)在Manifest.xml的application节点中声明android:name=”android.support.multidex.MultiDexApplication”。
(2)如果你已经有自己的Application类,让Application类继承MultiDexApplication;
(3)如果你不想让你的Application类去继承MultiDexApplication,那么可以选择重写attachBaseContext()方法:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
这样当你的应用方法数超过65K就会生成两个或更多dex文件打入apk包。
1.3 自定义主dex中必须要包含的类
如果有需求必须把某些类打入主dex文件,可以自行配置一个maindexlist.txt文件置于app目录下,并在txt文件内标明自定义想要被打入主dex文件的类,最后别忘了multidex的jar包中有9个类必须被打入主dex文件。maindexlist.txt文件如下所示:
//自定义类
com/calvin/util/Util.calss
//jar包中的9个类
android/support/multidex/BuildConfig.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/MultiDex$V4.class
android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/ZipUtil$CentralDirectory.class
android/support/multidex/ZipUtil.class
最后在Gradle中加入afterEvaluate节点进行如下配置即可:
afterEvaluate {
tasks.matching {
it.name.startsWith('dex')
}.each { dx ->
Def listFile = project.rootDir.absolutePath + '/app/maindexlist.txt'
if (dx.additionalParameters == null) {
dx.additionalParameters = []
}
dx.additionalParameters += '--multi-dex' //表示方法数越界生成多个dex
dx.additionalParameters += '--main-dex-list=' + listFile //类列表,这里即txt文件路径
dx.additionalParameters += '--minimal-main-dex' //表示只有main-dex-list指定的类会被置于主dex
}
}
2 总结
(1)方法数自己想办法能减少就尽量减少,实在不行就使用Multidex方案,Multidex解决方法数越界容易且高效,但是不可避免的是额外的dex文件会降低应用启动速度。
(2)在应用安装过程中系统会运行一个名为dexopt的程序来优化dex文件,dexopt使用LinearAlloc缓冲区来存储应用的方法信息。Android 2.x中该缓冲区只有5MB,4.x提高到了8MB或16MB。当方法数量过多(甚至不需要超过65K)时,可能会超过缓冲区容量限制而报错。
因此Multidex方案Maybe会在4.0以前的手机上失效。但是使用该方案产生很多个dex文件,缓冲区超过16MB一样会在4.0以后的手机上崩溃。所以在4.0以前的手机上需要做兼容性测试,4.0以后的手机上也不能因为有了Multidex方案而过于放纵~
3 5.0以后
从Android5.0开始,使用ART虚拟机代替Dalvik虚拟机,ART虚拟机在应用安装期间,会执行一个预编译的操作,扫描APK中所有的dex文件并把他们编译成一个单一的.oat文件,然后在应用运行的时候直接去加载这个.oat文件,而不是一个个的去加载.dex文件。
最后请大家多留言交流,还有多点赞支持~