Android uses android-support-multidex to solve the problem of Dex exceeding the limit of the number of methods, so that your application is no longer bursting

         With the continuous iteration of the application, the expansion of the business line, the application is getting bigger and bigger (for example, integrating various third-party SDKs or publicly supported jar packages, the project has high coupling, and there are more and more repetitive classes), I believe many people Have encountered the following errors:
UNEXPECTED TOP-LEVEL EXCEPTION:  
java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536  
at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501)  
at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282)  
at com.android.dx.merge.DexMerger.mergeMethodIds (DexMerger.java:490)  
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167)  
at com.android.dx.merge.DexMerger.merge (DexMerger.java:188)  
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)  
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)  
at com.android.dx.command.dexer.Main.run(Main.java:230)  
at com.android.dx.command.dexer.Main.main(Main.java:199)  
at com.android.dx.command.Main.main(Main.java:103)

       That's right, the number of Dex file methods in your application exceeds the maximum limit of 65536. In short, the application is overwhelmed.
        So let's see why this error occurs:
        in the Android system, all the code of an App All in a Dex file. Dex is a Jar-like archive that stores multiple Java compiled bytecodes. Because the Android system uses the Dalvik virtual machine, it is necessary to convert the class file compiled with Java Compiler into a class file that Dalvik can execute. It should be emphasized here that Dex, like Jar, is an archive file, which is still the bytecode file corresponding to the Java code. When the Android system starts an application, one step is to optimize Dex. This process is handled by a special tool called DexOpt. The execution process of DexOpt is executed when the Dex file is loaded for the first time. This process generates an ODEX file, Optimised Dex. The efficiency of executing ODex will be much higher than that of directly executing Dex files. But in the early Android system, DexOpt's LinearAlloc has limitations: Android 2.2 and 2.3 buffer only 5MB, Android 4.x increased to 8MB or 16MB. When the number of methods exceeds the buffer size, dexopt will crash and cannot be installed.
        In addition, due to the limitation of the DEX file format, the number of methods in a DEX file uses the native type short to index the method in the file, which is 4 A total of 65536 methods can be expressed in a byte, and the number of fields/classes is also limited. For DEX files, when all the class files required by the project are combined and compressed into one DEX file, that is, during the DEX process of Android packaging, the total number of methods that can be referenced by a single DEX file is limited to 65536 (self-developed and referenced code of the Android Framework and third-party class libraries).
        The most commonly used methods at present: (1) Application plug-in, such as using the plug-in framework I am participating in the development: https://github.com/singwhatiwanna/dynamic-load-apk , if you have any suggestions or related questions, welcome to Active participation on Github. (2) Divide Dex, multi-project: Compile the required .class file or Jar file and some source code together to generate a Jar file. Then use the dx tool provided by the Android SDK to convert the Jar file into a Dex file. (Refer to facebook: https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920 , you can also see it here on 2.3 Dynamically changing the solution to LinearAlloc buffering) These two methods are not in conflict. In addition to solving the application burst, plug-in has many other advantages. You can read my previous article and will not repeat it.
        Of course, Google seems to be aware of the current For the problem of the overwhelming number of application methods, a general solution has been provided in API 21, that is, android-support-multidex.jar. This jar package can support at least the version of API 4 (Android L and above versions will default to Support mutidex).
Let's see how to apply android-support-multidex.jar (the following are used in Anroid studio as an example, using eclipse development needs to install the gradle plugin, the others are basically the same):

First of all, you can use the --multi-dex configuration (build.gradle) to solve the problem. The generated Apk will contain multiple dex files, such as classes.dex, classes2.dex. As follows, build.gradle needs to be modified:
afterEvaluate {  
    tasks.matching {  
        it.name.startsWith('dex')  
    }.each { dx ->  
        if (dx.additionalParameters == null) {  
            dx.additionalParameters = []  
        }  
        dx.additionalParameters += '--multi-dex' // enable multidex  
  
        // optional  
        // dx.additionalParameters += "--main-dex-list=$projectDir/<filename>".toString() // enable the main-dex-list  
    }  
}

But the default Dalvik class loader only looks for classes.dex, so they need to be merged to be recognized.

Of course , now with the support of android.support.multidex.jar, everything will be very simple, first let's take a look The directory of the relevant source code, the specific principle analysis will be explained in the following articles:
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

Specific integration:
Add the following configuration to the project build.gradle
android {  
    defaultConfig {  
        // Enabling multidex support.  
        multiDexEnabled true  
    }  
}  
dependencies {  compile 'com.google.android:multidex:0.1'}

MultiDex implementation principle:
        When Apk is running, there is a dexpathlist, and in the source code of Multidex, the dexpathlist will be modified according to your system version number, and all dex will be added to the dexpathlist.


The next integration has two steps:
1. Import android-support-multidex.jar into the project from the sdk\extras\android\support\multidex\library\libs directory.
2. If your project already contains the Application class, let it inherit android.support.multidex. MultiDexApplication class,
     if your Application has inherited other classes and you don't want to make changes, there is another way to use it, override the attachBaseContext() method:
public class MyApplication extends FooApplication {  
    @Override  
    protected void attachBaseContext(Context base) {  
        super.attachBaseContext(base);  
        MultiDex.install(this);  
    }  
}

Finally give the complete configuration in build.gradle:
android {  
    compileSdkVersion 21  
    buildToolsVersion "21.1.0"  
  
    defaultConfig {  
        ...  
        minSdkVersion 14  
        targetSdkVersion 21  
        ...  
  
        // Enabling multidex support.  
        multiDexEnabled true  
    }  
    ...  
}  
  
dependencies {  
  compile 'com.android.support:multidex:1.0.0'  
}

Tips for using MutiDex

1. If you inherit MutiDexApplication or override the attachBaseContext() method in
Application. Notes on the logic in the Application class:
Static global variables in Application will be loaded before the instal() method of MutiDex, so It is recommended to avoid using static variables in the Application class to refer to classes in dex files other than the main classes.dex file, which can be modified as follows:
@Override  
    public void onCreate() {  
        super.onCreate();  
  
        final Context mContext = this;  
        new Runnable() {  
  
            @Override  
            public void run() {  
                // put your logic here!  
                // use the mContext instead of this here  
            }  
        }.run();  
    }

2. Although Google has solved the problem of the limitation of the total number of applications, it does not mean that developers can arbitrarily expand the scale of the project. Multidex still has some limitations:
  • The process of installing a DEX file to a device is very complicated, and if the second DEX file is too large, it can cause the app to become unresponsive. At this point ProGuard should be used to reduce the size of the DEX file.
  • Due to a bug in Dalvik linearAlloc, the application may not be able to launch in versions prior to Android 4.0. If your application supports these versions, you need to perform more tests.
  • Also because of the limitations of Dalvik linearAlloc, it may crash if a lot of memory is requested. Dalvik linearAlloc is a fixed size buffer. During the installation of the application, the system will run a program called dexopt to prepare the application for running on the current model. dexopt uses LinearAlloc to store application method information. Android 2.2 and 2.3 buffer only 5MB, Android 4.x increased to 8MB or 16MB. When the number of methods exceeds the buffer size, it will cause dexopt to crash.
  • The Multidex build tool does not yet support specifying which classes must be included in the first DEX file, so it may render certain class libraries (such as one that needs to access Java code from native code) unusable.

Avoiding too large applications and too many methods is still a problem that Android developers should pay attention to. Mihai Parparita's open source project dex-method-counts can be used to count the number of methods per package in the APK.

It is usually difficult for the developer's own code to reach such a limit on the number of methods, but with the addition of third-party class libraries, the number of methods will rapidly expand. Therefore, choosing a suitable class library is particularly important for Android developers.

Developers should avoid libraries like Google Guava, which contains over 13,000 methods. Try to use a Lite/Android version of the library designed for mobile applications, or use a small library instead of a large library, such as Google-gson instead of Jackson JSON. For data exchange formats such as Google Protocol Buffers, the standard implementation will automatically generate a large number of methods. The implementation using Square Wire can solve this problem very well.


FAQ

DexException: Library dex files are not supported in multi-dex mode, you may see the following error:
Error:Execution failed for task ':app:dexDebug'.  
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:  
    $ANDROID_SDK/build-tools/android-4.4W/dx --dex --num-threads=4 --multi-dex  
    ...  
  Error Code:  
    2  
  Output:  
    UNEXPECTED TOP-LEVEL EXCEPTION:  
    com.android.dex.DexException: Library dex files are not supported in multi-dex mode  
        at com.android.dx.command.dexer.Main.runMultiDex(Main.java:322)  
        at com.android.dx.command.dexer.Main.run(Main.java:228)  
        at com.android.dx.command.dexer.Main.main(Main.java:199)  
        at com.android.dx.command.Main.main(Main.java:103)

The --multi-dex option for dex conflicts with the precompiled library project, so if your application contains a referenced library project, you need to set precompile to false:
android {  
    // ...  
    dexOptions {  
        preDexLibraries = false  
    }  
}

OutOfMemoryError: Java heap space

If you see the following error at runtime:
UNEXPECTED TOP-LEVEL ERROR:  
java.lang.OutOfMemoryError: Java heap space

There is a field in dexOptions to increase the java heap memory size:
android {  
    // ...  
    dexOptions {  
        javaMaxHeapSize "2g"  
    }  
}

Developers using eclipse can refer to Google's official documentation
https://developer.android.com/tools/building/multidex.html#mdex-gradle
Need to install a plugin that supports gradle build, download address:
http://dist.springsource. com/release/TOOLS/gradle   (currently it may be necessary to learn and study soil)


Related materials:
1. MutiDex official documentation: https://developer.android.com/reference/android/support/multidex/MultiDex.html
2. http ://blog.osom.info/2014/10/multi-dex-to-rescue-from-infamous-65536.html is

attached with android-support-mutidex.jar download address: http://download.csdn.net/ detail/t12x3456/8143383

Supplementary Notes:
com.android.dex.DexException: Multiple dex files define L{package}/BuildConfig;

If you encounter this error, please check as follows:
1. Whether the package names of the main project and the dependent library project are duplicated
2. Check whether the main project and the dependent library project contain duplicate support.jar or other jar packages

Solution :
1. Modify the library project Package name
2. Delete the duplicate jar package
3. Manually add the lib package and add the following configuration
dependencies {  
            compile fileTree(dir: 'libs', include: ['*.jar'])  
            compile project(':lib-project-module')  
        }

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326992004&siteId=291194637