转: Android 使用android-support-multidex解决Dex超出方法数的限制问题

转自: 时之沙: http://blog.csdn.net/t12x3456

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误:

[java] view plaincopy

  1. UNEXPECTED TOP-LEVEL EXCEPTION:
  2. java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536
  3. at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501)
  4. at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282)
  5. at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490)
  6. at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167)
  7. at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
  8. at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
  9. at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
  10. at com.android.dx.command.dexer.Main.run(Main.java:230)
  11. at com.android.dx.command.dexer.Main.main(Main.java:199)
  12. at com.android.dx.command.Main.main(Main.java:103)

 没错,你的应用中的Dex 文件方法数超过了最大值65536的上限,简单来说,应用爆棚了.

        那么让我们看一下为什么会引起这种错误:

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

目前比较常用的方法:(1) 应用插件化,比如使用我正在参与开发的插件化框架 : https://github.com/singwhatiwanna/dynamic-load-apk ,如果有建议或者相关的问题,欢迎到Github上积极参与. (2) 分割Dex,多工程: 把所需要的.class文件或者是Jar文件和一些源码一起编译生成一个Jar文件。然后使用Android SDK提供的dx工具把Jar文件转成Dex文件。我们可以提前对它进行ODex操作,让它在被DexClassLoader加载的时候,跳过DexOpt的部分工作,从而加快加载的过程. 这两种方法并不冲突,插件化除了解决应用爆棚,还有很多其他的优点,可以看我之前的文章,不再复述.

当然,Google看来也意识到了目前应用方法数爆棚的问题, 目前在已经在API 21中提供了通用的解决方案,那就是android-support-multidex.jar. 这个jar包最低可以支持到API 4的版本(Android L及以上版本会默认支持mutidex).

让我们看一下如何应用android-support-multidex.jar(以下都以在Anroid studio中的使用为例,使用eclipse开发需要安装gradle插件,其他基本上相同):

首先可以用--multi-dex配置(build.gradle)进行解决,生成的Apk中将包含多个dex文件,比如classes.dex, classes2.dex. 如下,需要对build.gradle进行修改:

[java] view plaincopy

  1. afterEvaluate {
  2. tasks.matching {
  3. it.name.startsWith(‘dex‘)
  4. }.each { dx ->
  5. if (dx.additionalParameters == null) {
  6. dx.additionalParameters = []
  7. }
  8. dx.additionalParameters += ‘--multi-dex‘ // enable multidex
  9. // optional
  10. // dx.additionalParameters += "--main-dex-list=$projectDir/<filename>".toString() // enable the main-dex-list
  11. }
  12. }

但是默认的Dalvik 类加载器只会寻找classes.dex,所以需要将它们进行合并才能使得被识别

当然,现在有了android.support.multidex.jar的支持,一切都会变得非常简单,首先我们看一下相关源码的目录,具体的原理分析我会在之后的文章中进行讲解:

[java] view plaincopy

  1. android/support/multidex/BuildConfig.class
  2. android/support/multidex/MultiDex$V14.class
  3. android/support/multidex/MultiDex$V19.class
  4. android/support/multidex/MultiDex$V4.class
  5. android/support/multidex/MultiDex.class
  6. android/support/multidex/MultiDexApplication.class
  7. android/support/multidex/MultiDexExtractor$1.class
  8. android/support/multidex/MultiDexExtractor.class
  9. android/support/multidex/ZipUtil$CentralDirectory.class
  10. android/support/multidex/ZipUtil.class

具体集成:
将如下配置加入工程 classPath

[java] view plaincopy

  1. repositories {
  2. jcenter()
  3. }
  4. dependencies {
  5. compile ‘com.google.android:multidex:0.1‘
  6. }

MultiDex实现原理:

Apk在运行的时候,有一个dexpathlist,而Multidex的源码中,会根据你的系统版本号对dexpathlist做修改,将所有的dex都添加到dexpathlist中.

接下来集成有两个步骤:

一. 从sdk\extras\android\support\multidex\library\libs 目录将android-support-multidex.jar导入工程中

二. 如果你的工程中已经含有Application类,那么让它继承android.support.multidex.MultiDexApplication类,

     如果你的Application已经继承了其他类并且不想做改动,那么还有另外一种使用方式,覆写attachBaseContext()方法:

[java] view plaincopy

  1. public class MyApplication extends FooApplication {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. MultiDex.install(this);
  6. }
  7. }

最后给出build.gradle中的完整配置:

[java] view plaincopy

  1. buildscript {
  2. repositories {
  3. jcenter()
  4. }
  5. dependencies {
  6. classpath ‘com.android.tools.build:gradle:0.13.3‘
  7. classpath ‘jp.leafytree.gradle:gradle-android-scala-plugin:1.1‘
  8. }
  9. }
  10. apply plugin: ‘com.android.application‘
  11. apply plugin: ‘jp.leafytree.android-scala‘
  12. repositories {
  13. jcenter()
  14. }
  15. android {
  16. compileSdkVersion 21
  17. buildToolsVersion ‘21.0.2‘
  18. defaultConfig {
  19. applicationId ‘some.app‘
  20. minSdkVersion 19
  21. targetSdkVersion 19
  22. versionCode 1
  23. versionName ‘1.0‘
  24. }
  25. }
  26. dependencies {
  27. compile ‘com.google.android:multidex:0.1‘
  28. compile ‘com.android.support:support-v4:19.0.1‘
  29. compile ‘com.google.android.gms:play-services:5.0.77‘
  30. compile ‘org.scala-lang:scala-library:2.11.2‘
  31. compile ‘org.scaloid:scaloid_2.11:3.4-10‘
  32. }

使用MutiDex的主意事项

 

一. 如果你继承了MutiDexApplication或者覆写了Application中的attachBaseContext()方法.

Application类中逻辑的注意事项:

Application 中的静态全局变量会比MutiDex instal()方法优先加载,所以建议避免在Application类中使用main classes.dex文件中可能使用到的静态变量,可以根据如下所示的方式进行修改:

[java] view plaincopy

  1. @Override
  2. public void onCreate() {
  3. super.onCreate();
  4. final Context mContext = this;
  5. new Runnable() {
  6. @Override
  7. public void run() {
  8. // put your logic here!
  9. // use the mContext instead of this here
  10. }
  11. }.run();
  12. }

常见问题

DexException: Library dex files are not supported in multi-dex mode,你可能会见到如下的错误:

[java] view plaincopy

  1. Error:Execution failed for task ‘:app:dexDebug‘.
  2. > com.android.ide.common.internal.LoggedErrorException: Failed to run command:
  3. $ANDROID_SDK/build-tools/android-4.4W/dx --dex --num-threads=4 --multi-dex
  4. ...
  5. Error Code:
  6. 2
  7. Output:
  8. UNEXPECTED TOP-LEVEL EXCEPTION:
  9. com.android.dex.DexException: Library dex files are not supported in multi-dex mode
  10. at com.android.dx.command.dexer.Main.runMultiDex(Main.java:322)
  11. at com.android.dx.command.dexer.Main.run(Main.java:228)
  12. at com.android.dx.command.dexer.Main.main(Main.java:199)
  13. at com.android.dx.command.Main.main(Main.java:103)

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

[java] view plaincopy

  1. android {
  2. // ...
  3. dexOptions {
  4. preDexLibraries = false
  5. }
  6. }

OutOfMemoryError: Java heap space

当运行时如果看到如下错误:

[java] view plaincopy

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

dexOptions中有一个字段用来增加java堆内存大小:

[java] view plaincopy

  1. android {
  2. // ...
  3. dexOptions {
  4. javaMaxHeapSize "2g"
  5. }
  6. }

使用eclipse的开发人员可以参考Google官方文档

https://developer.android.com/tools/building/multidex.html#mdex-gradle

需要安装支持gradle构建的插件,下载地址:

http://dist.springsource.com/release/TOOLS/gradle  (目前可能需要FQ)

参考相关资料:

1. MutiDex 官方文档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

另附android -support-mutidex.jar下载地址: http://download.csdn.net/detail/t12x3456/8143383

补充注意事项:

[java] view plaincopy

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

如果遇到这个错误请进行如下检查:

1. 主工程与依赖library工程包名是否重复
2. 检查主工程与依赖library工程是否含有重复的support.jar或者其他jar包

 

解决方案:

1. 修改library工程包名

2. 删除重复jar包

3.手工添加lib包,增加如下配置

[java] view plaincopy

    1. dependencies {
    2. compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
    3. compile project(‘:lib-project-module‘)
    4. }
时间: 2024-11-08 23:21:21

转: Android 使用android-support-multidex解决Dex超出方法数的限制问题的相关文章

Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚

如有转载,请声明出处: 时之沙: http://blog.csdn.net/t12x3456    (来自时之沙的csdn博客) 随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 6553

Android 使用android-support-multidex解决Dex超出方法数的限制问题

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:

Dex文件方法数超过65536怎么破?

你的应用中的Dex 文件方法数超过了最大值65536的上限,会提示你: UNEXPECTED TOP-LEVEL EXCEPTION:java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501)at com.android.dx.merge.DexMerger$IdMerger.me

android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题!

ndroid-Easy-MultiDex 项目地址:TangXiaoLv/Android-Easy-MultiDex 简介:Android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题! 注 1:不想看前半部分的话可以直接跳过到最下面配置部分.注 2:本插件是基于DexKnifePlugin 1.5.6优化改造而来,感谢 ceabie 的无私奉献. 填坑之路 坑 1:65536 ,So easy! 原因:Dalvik 的 invoke-kind 指令集中,method refere

Android 65K问题之Multidex原理分析及NoClassDefFoundError的解决方法

Android 65K问题相信困惑了不少人,尽管AS的出来能够通过分dex高速解决65K问题,可是同一时候也easy由于某些代码没有打包到MainDex里引起NoClassDefFoundError. 随着5.0的推出,Android也放出了Multidex Support Library来解决问题. Multidex Support Library能够直接分包处理65K问题.而且不会发生NoClassDefFoundError的情况. 1.使用的话.首先加入依赖库: //分包multiDexE

android 方法数超过65k,解决dex方法数超过65536

最近有朋友在问我,为什么我就加了一个类/一个库突然跑不起来了. 排查方式: 1.确认你的代码/引用没有问题 2.检查是否是65k问题 今天主要是解决 排查方式2的步骤,这个原因主要是因为你的apk包方法数过大. 现在解决这个已经很方便了: 方式一(繁琐):程序分包,这个比较繁琐:需要对jvm加载Class的方式有足够的了解 方式二(快速,使用AS): 1.使用google提供的分包库 implementation 'com.android.support:multidex:1.0.2' impl

使用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.

Android 解决方法数 65536 (65k) 限制

可能出现的错误信息: Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536 说明:这个方法是谷歌提供的.链接如下:https://developer.android.com/studio/build/multidex.html 解决步骤: 1.步骤1: android { compileSdkVersion 21 buildToolsVersion "21.1.

Android应用解决65K方法数限制

近日,Android Developers在Google+上宣布了新的Multidex支持库,为方法总数超过65K的Android应用提供了官方支持. 如果你是一名幸运的Android应用开发者,正在开发一个前景广阔的应用,不断地加入新功能.添加新的类库,那么终有一天,你会不幸遇到这个错误: Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536 这个错误是And