The number of method references in a .dex file cannot exceed 64K
Most android developers have been seen this error message before. This problem occurs when build android project to APK file.
What does it mean? Why it happens? and how can we fix it?
An introduction to the .dex file
In java, when .java was compiled it will be .class file to execute with Java VM. But Android use Dalvik VM (pre-lollipop) instead of Java VM to execute .dex file that compressed from .class file because it compact and suitable for mobile device like as smartphone more than .class file.
So when android application was compiled. The .java file will compiled to .class and compiled to .dex again. Then it will zip with resource file to .apk file.
The limitation of .dex file is maximum method count support in this file is only 65,536 methods. These include the android framework, 3rd-party library and your code.
Exceed 65K Method that means method count more than 65,536 methods
That’s it! This problem because of limitation of .dex file. Sometime you may have seen 65K or 64K wording. That are same because 65,536 / 1.024 = 64,000.
So it’s normally if your big project stuck in this problem. If your project isn’t large too much. I think you should check your project by follow this article.
How can we fix it?
Most developer fix this problem by use MultiDex. In fact. It shouldn’t always use MultiDex. but you can try to use another way to fix this problem before.
1. Reduce dependencies in your project
Because of exceeding method count in your project. So you should fix the problem by reduce dependencies first.
Check your project that contain with unused dependencies or not. If any dependencies can reduce or replace with another dependencies that compact than it, do it. For example, I found some projects are use Picasso and Glide together. Why don’t you use one at all?
Most problems that I found from another developers is use Google Play Services in them project like this.
implementation 'com.google.android.gms:play-services:8.4.0'
A pack of Google Play Services dependencies is very big, contain with 58,180 methods!!
So the best way is choosing only some dependencies in Google Play Services that you really want to use it.
implementation 'com.google.android.gms:play-services-location:8.4.0'
implementation 'com.google.android.gms:play-services-maps:8.4.0'
implementation 'com.google.android.gms:play-services-ads:8.4.0'
These dependencies are use only 27,766 methods. It look still too much method count for me but it is inevitable, because these dependencies are required some important dependencies such as Android Support v4, Base Google Play Services and Support Annotation.
Dependencies reducing by remove unnecessary dependencies is very important. You should do it first before use another way. Not only fix the exceed method count problem, but project building with gradle will be faster.
2. Set minimum SDK version to 21 or higher
This isn’t great way, if your application need to support pre-lollipop version. But if based-on lollipop version (May required any feature in Android Lollipop)
Why it worked when change minimum SDK to 21? That’s because of Android 5.0 or higher are use ART (Android Runtime) that supported MultiDex instead of Dalvik. So ART can support more than 65,536 methods.
Inside the ART, when .class was compiled to .dex (Can be more than one). AOT (Ahead-of-Time) will compile .dex to .oat after that.
That why a project that required minimum SDK 21 will use ART and say goodbye to Over 65K Methods problem, yeah!
3. Use Proguard to reduce useless method
This solution is suits for Release build more than Debug build. Because it take a longer time and difficult to log analyze from Logcat.
Normally, Proguard will shrink and Obfuscate the code when you build a project, so unused method will be removed (But you can keep some method or class by config a proguard-rules.pro file) and also reduce total method count of your project.
4. OK! I give up and use MultiDex
MultiDex is the last way, if 3 ways that I mentioned aren’t suitable for you. MultiDex allows you to build an APK with Dalvik by contain with multiple .dex with over 65,536 methods. Google has publish the MultiDex library to support with pre-Lollipop that use Dalvik to build project to .apk by required Android SDK Build Tools version 21.1 or higher.
Limitation of MultiDex library
- May occurs ANR while app launching if .dex files too large.
- Should be define minimum SDK to version 14 or higher.
- MulitDex consume more memory and may crash while app running if allocation memory is over limit.
- Take more build time when you build the project.
How to use MultiDex in your project
Add MultiDex dependencies in build.gradle
your target module like this.
// build.gradle
android {
/* ... */
defaultConfig {
/* ... */
multiDexEnabled true
}
}
dependencies {
/* ... */
implementation 'com.android.support:multidex:1.0.0'
}
In Android Manifest, <application>
must use MultiDexApplication.
<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<application
...
android:name="android.support.multidex.MultiDexApplication">
<!-- ... -->
</application>
</manifest>
MultiDexApplication class will manage your project to support with multi .dex files.
But if you’re using custom Application class. Just declare MultiDex method in to your class by follow this.
// MainApplication.kt
class MainApplication: Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
And then use your custom Application class instead of MultiDexApplication.
Use MultiDex while under development.
Because use MultiDex is take a long time to build a project. So don’t use it when your project is under development. It should be use in production release only. But I recommend you to use ART in you under development project by set minimum SDK version to 21 or higher version by use Build Variant to separate build type between develop and production.
// build.gradle
android {
/* ... */
productFlavors {
develop {
minSdkVersion 21
}
production {
minSdkVersion 16
multiDexEnabled true
}
}
}
How to check total method count in your project?
I use DexCount ny KeepSafe, the gradle plugin to show method count after finish the gradle building. It’s very easy to use it. Just declare like this into build.gradle
of your target module.
// build.gradle
android {
/* ... */
productFlavors {
develop {
minSdkVersion 21
}
production {
minSdkVersion 16
multiDexEnabled true
}
}
}
When gradle building has finish, it will be show total method count in console window.
The report files is the one thing that I like it. Because it show how many method count in the each class in .txt files.
Conclusion
It is common for big project to facing with the Over 65K Methods problem. (yeah, me too) But using MultiDex isn’t the best way to solve this problem. It last way if you can fix this problem with another way. Reduce dependencies is the first thing that you have to do.
And recommend you to use 3rd party plugin to make the method count checking more convenient.