Understanding Multidex in Android

Understanding Multidex in Android

In Java, if we compile our code then that code is converted into a .class file by the compiler because our machine understands that .class file. The same is the process for the Android Application. In Android, the compiler converts our source code into DEX(Dalvik Executable) file.

So, in this blog, we will learn about Dex and Multidex in Android. Especially, this blog is for those Android developers who get 64K method limit exceeded error while building APK. This error comes due to DEX. So, in this blog, we will try to gain more knowledge about Dex and Multidex in Android.

The timeline of this blog is as follows:

  • Android build system
  • Multidex in Android
  • Enabling Multidex support in Project
  • Limitations of Multidex support library
  • Conclusion

Android Build System

Before moving on to DEX, let's revise some concepts of the build system of Android. Android compiles the resources and source code of our app and packages them into APKs. Conversion of our project into an APK requires many tools and involves many processes. You can understand the build process with the help of the below diagram:

Image Credit: Android Developer website

Understanding Multidex in Android

The build process of a typical Android App can be summarized as below:

  1. The compilers convert the source code into DEX (Dalvik Executable) files, which include the bytecode that runs on Android devices.
  2. After having the DEX files, the APK Packager combines the DEX files and compiled resources into a single APK.
  3. After that, the APK Packager signs the APK.
  4. Before generating the final APK, various methods are followed to optimize the code so as to avoid the unused code.

Multidex in Android

In Android, the compilers convert your source code into DEX files. This DEX file contains the compiled code used to run the app. But there is a limitation with the DEX file. The DEX file limits the total number of methods that can be referenced within a single DEX file to 64K i.e. 65,536 methods. So, you can't use more than 64K methods in a particular DEX file. These 64K methods include Android framework methods, library methods, and methods in our code also. This limit of 64K is referred to as the "64K reference limit".

So, if our app exceeds 65,536 methods, we will encounter a build error that indicates our app has reached the limit of the Android build architecture. The error is as follows:

Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

Older versions of the build system report a different error, which also indicates the same problem:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

Both the above error are known as 64K reference limit i.e we are trying to use more than 64K methods in our code. So, here comes the role of Multidex support in our Android Project. Next time if you want to use more than 64K methods in your project then you can use the Multidex to achieve this.

If you are getting some type of DEX error then before configuring your app for multidex to enable the use of 64K or more reference methods, you should try to reduce the total number of reference methods that are being used by our app. Try the following strategies to avoid using 64K reference methods:

  1. Manage dependencies: While importing some dependencies for our project, sometimes we import each and every library and use only a few of them. So, instead of keeping all those dependencies, we can keep only the required one.
  2. Remove unused code: Enable code shrinking in your project. By doing so, we are not shipping unused code with our APK.

In the next part of this blog, we will learn how to use the Multidex support for our project that has more than 64K methods.

Enabling Multidex support in Project

Here, we will see how to enable multidex for following:

  • API level lower than 21: That is if your minSdkVersion is set to lower than 21.
  • API level 21 and higher.

Note: Follow only one of the following based on the minSdkVersion.

  • Multidex support for API level lower than 21
  • Multidex support for API level 21 and higher

Multidex support for API level lower than 21

For executing app code, versions of Android lower than Android 5.0 (API level 21) use the Dalvik runtime, and the limitation of using Dalvik is that you can't use more than one classes.dex bytecode file per APK. To overcome this limitation, you will have to add the Multidex support library.

To add the multidex support library to your project for API level lower than 21, add the following dependency in your build.gradle file.

dependencies {
    implementation 'androidx:multidex:{latest-version}'
}

If you aren't using AndroidX, add the following support library dependency instead:

dependencies {
  implementation 'com.android.support:multidex:{latest-version}'
}

By adding this library, your app can manage the access of additional DEX files. In other words, if you are having more than 64K methods, then you will be having more than one DEX file and these DEX files will be managed by using this multidex support library.

Then, modify the module-level build.gradle file to enable multidex using multiDexEnabled true.

android {
    defaultConfig {
 ...
        minSdkVersion 15 
        targetSdkVersion 28
        multiDexEnabled true
 }
 ...
}

dependencies {
 implementation 'androidx:multidex:{latest-version}'
}

Then, depending on whether you override the Application class, perform one of the following:

1. If you do not override the Application class, edit your manifest file to set android:name in the <application> tag as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example">
    <application
            android:name="android.support.multidex.MultiDexApplication" >
        ...
    </application>
</manifest>

2. If you do override the Application class, change it to extend MultiDexApplication (if possible) as follows:

public class MyApplication extends MultiDexApplication { ... }

3. Or if you do override the Application class but it's not possible to change the base class, then you can instead override the attachBaseContext() method and call MultiDex.install(this) to enable multidex:

public class MyApplication extends SomeOtherApplication {
  @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
  }
}

You are all set now.

This was all about the API level lower than 21. Now, let's move to the next one.

Multidex support for API level 21 and higher

Your task becomes easier if you are making an app for Android version 5.0 (API level 21) or higher. API level 21 uses a runtime called ART which supports loading multiple DEX files from APK files. So, you do NOT need to add the support library for multidex in Android 5.0 or higher.

Now, for API level 21 or higher, you need to set multiDexEnabled to true in your module-level build.gradle file, as shown here:

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

Then, depending on whether you override the Application class, perform one of the following:

1. If you do not override the Application class, edit your manifest file to set android:name in the <application> tag as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example">
    <application
            android:name="android.support.multidex.MultiDexApplication" >
        ...
    </application>
</manifest>

2. If you do override the Application class, change it to extend MultiDexApplication (if possible) as follows:

public class MyApplication extends MultiDexApplication { ... }

3. Or if you do override the Application class but it's not possible to change the base class, then you can instead override the attachBaseContext() method and call MultiDex.install(this) to enable multidex:

public class MyApplication extends SomeOtherApplication {
  @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
  }
}

You are all set now.

So, now when you build your app, one primary DEX file will be constructed, and supporting DEX files will also be added to it. The primary DEX file is normally marked as classes.dex and other supporting DEX files as classes1.dex, classes2.dex, ... and so on.

Limitations of Multidex support library

A good Android Developer know about the benefits of using some library but a professional developer also knows the limitations of using that library

The multidex support library has some known limitations that we should be aware of before using it in our app. Some of the limitations are:

  • If your secondary DEX file is larger than the primary DEX file, then you may encounter some Application Not Responding (ANR) error. In this case, you should apply code shrinking to minimize the size of DEX files and remove unused portions of code.
  • If you are targeting API levels lower than 21, test thoroughly on those versions of the platform, because your app might have issues at startup or when particular groups of classes are loaded.

Code Shrinking can reduce or possibly eliminate these issues.

Conclusion

If you are working on an Android application that includes more than 64K methods then to avoid the 64K reference limit, you can use Multidex in your application. I am sure that after reading this blog, you all are familiar with the Multidex property of Android. So, implement this in your project, but before doing so, make sure that your code is totally shrunk because code shrinking will help in reducing or possibly eliminating the Dex error.

Happy learning :)

Team MindOrks.