MultiDex
Recently, optimize upgrade project, finally reported the 64K method limit problem, and record the solution conveniently;
Reasons for 64K limit
The Android APK file is essentially a compressed file that contains the classes.dex file, an executable Dalvik byte code file that holds all the compiled Java code.The Dalvik executable specification limits the maximum number of methods a single DEX file can drink to 65536, including the Android Framework, third-party libraries referenced by APP, and its own methods (which feels like a design mistake);
Use MultiDex to resolve 64K restrictions
Before Android 5.0
Before 5.0, the system used a Dalvik virtual machine to execute Android applications. Dalvik generated only one DEX file for each APK. To avoid exceeding the 64K limit, we could only split one DEX into several dex, similar to classes.dex,classes2.dex,classes3.dex. When the application started, the program loaded the main DEX first, and then the main dex.Add it to the other Dex in turn; Google has launched a library called MultiDex Support Library, which can be found under / extras/android/support/mulidex/;
After Android 5.0
After 5.0, the system began to use ART's virtual machine instead of Dalvik's. ART naturally supports APK to load multiple dex files. It can scan all dex files directly and compile them into an oat file, referring to loading oat directly instead of one loading dex file.
Configuring with MultiDex
MultiDex is mainly configured in Gradle files, but you do not only need to configure Gradle files in Module, but also Gradle files in the project root directory.
First, let's configure the Gradle file in Module with the following code:
apply plugin: 'com.android.application'
android {
// productFlavors are two sets of run configurations set up to avoid reloading the DEX once per run
productFlavors {
dev {
minSdkVersion 21
}
prod {
minSdkVersion 14
}
}
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.example.itgungnir.testmultidex"
minSdkVersion 11
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// Set MultiDex Available
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// Ensure that other LIBS are not preDex
dexOptions {
preDexLibraries = false
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
// MultiDex Dependency
compile 'com.android.support:multidex:1.0.1'
}
After configuring the Gradle file under Module, configure the Gradle file under Project s.The code in the file is as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
// Ensure that all files specified in the dex_files file are loaded into Main Dex
afterEvaluate {
tasks.matching {
it.name.startsWith('dex')
}.each { dx ->
if (dx.additionalParameters == null) {
dx.additionalParameters = []
}
dx.additionalParameters += '--multi-dex'
dx.additionalParameters += "--main-dex-list=$projectDir/dex_files".toString()
}
}
As you can see, there is mainly a block of afterEvaluate code added here, and dex_files on the last line is a.Txt file that holds all the files you want to load into MainDex by default.This dex_files file is in the same directory as this Gradle file. Here is the code in the dex_files.txt file (you can add it as needed):
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
Finally, you need to inject MultiDex into the project's Application file with the following code:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Inject MultiDex into the project
// The attachBaseContext method is executed before onCreate.Is the way developers can control the earliest execution of an application
MultiDex.install(this);
}
}
Finally, remember to configure Application in Manifest
Improving build efficiency
After adding MultiDex to your project, you click the Build button and find that it's not as fast as it used to be; if it's a very large application, it's incredibly fast; to reduce the build time added by pouring MultiDex into the development phase, we can use productFlavors to build it in the main module build.gradle file of the projectTwo flavor s, one for development and one for production;
android{
productFlavors{
dev{
//Smiling Version in Development
minSdkVersion 21
}
prod{
//Actual minimum version of app
minSdkVersion 14
}
}
}
Once the above configuration is complete, we can use devDebug variant to build our application, which combines the configuration of dev's productFlavor with debug's buildType, that is, the resulting APK will not use ProGuard;
Next we show how to use devDebug, a Build Variant, using the command line:
./gradlew installDevDebug
In Android Studio, click Build Variant on the right to open the corresponding module and select devDebug.