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

摘要:
因为Android系统使用Dalvik虚拟机,所以需要把使用JavaCompiler编译之后的class文件转换成Dalvik能够执行的class文件。当Android系统启动一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。这个过程会生成一个ODEX文件,即OptimisedDex。但是在早期的Android系统中,DexOpt的LinearAlloc存在着限制:Android2.2和2.3的缓冲区只有5MB,Android4.x提高到了8MB或16MB。然后使用AndroidSDK提供的dx工具把Jar文件转成Dex文件。

如有转载,请声明出处: 时之沙:http://blog.csdn.net/t12x3456 (来自时之沙的csdn博客)

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

  1. UNEXPECTEDTOP-LEVELEXCEPTION:
  2. java.lang.IllegalArgumentException:methodIDnotin[0,0xffff]:65536
  3. atcom.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501)
  4. atcom.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282)
  5. atcom.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490)
  6. atcom.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167)
  7. atcom.android.dx.merge.DexMerger.merge(DexMerger.java:188)
  8. atcom.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
  9. atcom.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
  10. atcom.android.dx.command.dexer.Main.run(Main.java:230)
  11. atcom.android.dx.command.dexer.Main.main(Main.java:199)
  12. atcom.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的LinearAlloc存在着限制:Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时,会造成dexopt崩溃,导致无法安装.

另外由于DEX文件格式限制,一个DEX文件中method个数采用使用原生类型short来索引文件中的方法,也就是最多表达65536个method,field/class的个数也均有此限制。对于DEX文件,则是将工程所需全部class文件合并且压缩到一个DEX文件期间,也就是Android打包的DEX过程中, 单个DEX文件可被引用的方法总数被限制为65536(自己开发以及所引用的Android Framework和第三方类库的代码).

目前比较常用的方法:(1) 应用插件化,比如使用我正在参与开发的插件化框架 :https://github.com/singwhatiwanna/dynamic-load-apk,如果有建议或者相关的问题,欢迎到Github上积极参与. (2) 分割Dex,多工程: 把所需要的.class文件或者是Jar文件和一些源码一起编译生成一个Jar文件。然后使用Android SDK提供的dx工具把Jar文件转成Dex文件。(可参考facebook:https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920,这里边还可以看到在2.3上动态改变LinearAlloc缓冲的解决思路) 这两种方法并不冲突,插件化除了解决应用爆棚,还有很多其他的优点,可以看我之前的文章,不再复述.

当然,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进行修改:

  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'//enablemultidex
  9. //optional
  10. //dx.additionalParameters+="--main-dex-list=$projectDir/<filename>".toString()//enablethemain-dex-list
  11. }
  12. }

但是默认的Dalvik 类加载器只会寻找classes.dex,所以需要将它们进行合并才能使得被识别
当然,现在有了android.support.multidex.jar的支持,一切都会变得非常简单,首先我们看一下相关源码的目录,具体的原理分析我会在之后的文章中进行讲解:

  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

具体集成:
将如下配置加入工程build.gradle

  1. android{
  2. defaultConfig{
  3. //Enablingmultidexsupport.
  4. multiDexEnabledtrue
  5. }
  6. }
  7. dependencies{compile'com.google.android:multidex:0.1'}

MultiDex实现原理:

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

接下来集成有两个步骤:

一. 从sdkextrasandroidsupportmultidexlibrarylibs 目录将android-support-multidex.jar导入工程中

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

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

  1. publicclassMyApplicationextendsFooApplication{
  2. @Override
  3. protectedvoidattachBaseContext(Contextbase){
  4. super.attachBaseContext(base);
  5. MultiDex.install(this);
  6. }
  7. }

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

    1. android{
    2. compileSdkVersion21
    3. buildToolsVersion"21.1.0"
    4. defaultConfig{
    5. ...
    6. minSdkVersion14
    7. targetSdkVersion21
    8. ...
    9. //Enablingmultidexsupport.
    10. multiDexEnabledtrue
    11. }
    12. ...
    13. }
    14. dependencies{
    15. compile'com.android.support:multidex:1.0.0'
    16. }

免责声明:文章转载自《Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚(转)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux-npm install命令&amp;amp;脚本命令unity 2d 和 NGUI layer下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

修改Android中strings.xml文件, 动态改变数据

有些朋友可能会动态的修改Android中strings.xml文件中的值,在这里给大家推荐一种简单的方法。strings.xml中节点是支持占位符的,如下所示: <string name="data">整数型:%1$d,浮点型:%2$.2f,字符串:%3$s</string> 其中%后面是占位符的位置,从1开始,          ...

SwitchButton 开关按钮 的多种实现方式

刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心。 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果。 起初我在android上我只会使用CheckBox去满足对应的功能。后来,查看开发文档发现,android也有了自己的原生态开关控件,并且在4.0版本中又优化加入了新的类似控件--Swi...

android在windows下面coco2dx平台搭建以及一些常见问题的解决

  最近因为参加比赛一些coco2dx的游戏,并且跨平台移植 ,废了好几天的时间,终于搞定了coco2dx的环境配置以及移植的全过程,在这片文章里面先说明一下我的coco2dx在windows下开发配置 闲话不说,直接上正文吧 1.首先,配置android开发环境(JAVA环境,eclipse+adt), 这个应该不用多说了吧   不明白的朋友们可以去参考...

Android开发之查看应用包名package和入口activity名称的方法

使用android自动化测试工具monkeyrunner启动应用时,需要填写被测程序的包名和启动的Activity,以下有两种查看应用包名package和入口activity名称的方法:方法一:使用aapt //aapt是sdk自带的一个工具,在sdkuilds-tools目录下1.以ES文件浏览器为例,命令行中切换到aapt.exe目录执行:aapt d...

Android 2.1 源码结构分析

Android 2.1   |-- Makefile   |-- bionic (bionic C库)   |-- bootable (启动引导相关代码)   |-- build (存放系统编译规则及generic等基础开发包配置)   |-- cts (Android兼容性测试套件标准)   |-- dalvik (dalvik JAVA虚拟机)   |-...

Android开发之权限列表

权限定义 功能 android.permission.ACCESS_CHECKIN_PROPERTIES 允许读写访问"properties"表在checkin数据库中,改值可以修改上传 android.permission.ACCESS_COARSE_LOCATION 允许一个程序访问CellID或WiFi热点来获取粗略的位置 andro...