记录今天解决的BUG问题
Android 方法数 65k 问题
- 什么是方法数 65k 问题?
在 Andorid 中单个 dex 文件所能包含的最大方法数为 65536,这包含 Android FrameWork、依赖的 jar 包以及应用本身的代码中所有的方法,当应用的方法达到 65536 后,编译器就无法完成编译,会抛出异常
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
- 为什么会出现这个异常?
这个异常是 Android 应用的方法总数限制造成的。Android 平台的 Java 虚拟机 Dalvik 在执行 DEX 格式的 Java 应用程序时,使用原生类型 short 来索引 DEX 文件中的方法。这意味着单个 DEX 文件可被引用的方法总数被限制为 65536。通常 APK 仅包含一个 classes.dex 文件,因此 Android 应用的方法总数不能超过这个数量。
3.解决方法
有以下几种解决方法:
1.加大 Proguard 的力度来减小 DEX 的大小和方法数,但这是治标不治本的方案,随着业务代码的添加,方法数终究会到达这个限制;
2.一种是插件化方案;
3.谷歌提供了一个 MultiDex 的分包方案,当方法数超过 65536 的时候,生成多个 dex 文件,把应用启动时必须用到的类和该类的直接引用类放到 Main dex 中,把其他类放到 Second dex 中。当应用启动之后,动态加载 Second dex,从而避免 65k 问题(建议);
这里介绍的是Multidex分包方案
- 修改 Gradle 配置文件,启用 MultiDex 并包含 MultiDex 支持:
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
...
minSdkVersion 22
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//启动 MultiDex 支持
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dexOptions {
//设置虚拟机堆内存大小,避免编译期间OOM,一般设置4g就够了
javaMaxHeapSize "4g"
}
}
...
dependencies {
...
//使用google提供的分包库
implementation 'com.android.support:multidex:1.0.2'
implementation 'com.android.support:multidex-instrumentation:1.0.2'
...
}
- 让应用支持多 DEX 文件,在官方文档中描述了三种可选方法:
//
// 1. 在 AndroidManifest.xml 的 application 中声明 android.support.MultiDex.MultiDexApplication;
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.MultiDex.myapplication">
<application
...
android:name="android.support.MultiDex.MultiDexApplication">
...
</application>
</manifest>
// 2.如果你已经有自己的 Application 类,让其继承 MultiDexApplication;
public class MyApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
}
}
//3. 如果你的 Application 类已经继承自其它类,你不想/能修改它,那么可以重写 attachBaseContext() 方法: 并在 AndroidManifest 中添加以下声明:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.MultiDex.myapplication">
<application
...
android:name="android.support.MultiDex.MultiDexApplication">
...
</application>
</manifest>