首页 > 代码库 > 使用android-support-multidex解决Android方法数超过65535的问题

使用android-support-multidex解决Android方法数超过65535的问题

随着应用不断更新,业务的不断增加, 应运而生的应用可能需要集成了各种第三方library,相信很多人都遇到过如下类似的错误:

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) 

这就是你的App中方法数超过了65535了,那这种问题发生的具体原因是什么呢?
在Android系统中,一个App的所有代码都在一个Dex文件里面。Dex是一个类似Jar的存储了多有Java编译字节码的归档文件。因为Android系统使用Dalvik虚拟机,所以需要把使用Java Compiler编译之后的class文件转换成Dalvik能够执行的class文件。这里需要强调的是,Dex和Jar一样是一个归档文件,里面仍然是Java代码对应的字节码文件。当Android系统启动一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件,即Optimised Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中,DexOpt有一个问题,也就是这篇文章想要说明并解决的问题。DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过65536个。当一个项目足够大的时候,显然这个方法数的上限是不够的。尽管在新版本的Android系统中,DexOpt修复了这个问题,但是我们仍然需要对低版本的Android系统做兼容.

下面就说下使用android-support-multidex的具体配置

  1. 在build.gradle中打开multidex的支持
android {  
    compileSdkVersion 23  
    buildToolsVersion "25"  
    defaultConfig {  
        ...  
        minSdkVersion 18  
        targetSdkVersion 20  
        ...  
        // Enable multidex support.  
        multiDexEnabled true  
    }  
    ...  
}

2.引入multidex的库依赖

dependencies {  
  compile ‘com.android.support:multidex:1.0.0‘  
} 

3.配置Application,以下两种方式任选其一即可

  • 继承MutiDexApplication
public class BsApplication extends MutiDexApplication {
}
  • 覆写Application中的attachBaseContext()方法
public class BsApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

常见问题
1. DexException: Library dex files are not supported in multi-dex mode错误


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)  

这是由于dex 的multi-dex 选项设置与预编译的library工程有冲突,因此如果你的应用中包含引用的lirary工程,需要将预编译设置为false:

android {   
    dexOptions {  
        preDexLibraries = false  
    }  
} 

2.OutOfMemoryError: Java heap space错误

UNEXPECTED TOP-LEVEL ERROR:  
java.lang.OutOfMemoryError: Java heap space 

这是因为堆栈内存不足造成的,在dexOptions中增加java堆栈内存大小

android {   
    dexOptions {  
        javaMaxHeapSize "2g"  
    }  
}  
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    使用android-support-multidex解决Android方法数超过65535的问题