• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

Android

Android应用65K方法数Dex Error

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/Android/2019/0816/601.html

 
     随着常州微信公众平台应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误:
 
 
<span style="color:#ff0000;">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)  </span>
近日,Android Developers在Google+上宣布了新的Multidex支持库,为方法总数超过65K的Android应用提供了官方支持。
 
如果你是一名幸运的Android应用开发者,正在开发一个前景广阔的应用,不断地加入新功能、添加新的类库,那么终有一天,你会不幸遇到这个错误:
 
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
 
这个错误是Android应用的方法总数限制造成的。Android平台的Java虚拟机Dalvik在执行DEX格式的Java应用程序时,使用原生类型short来索引DEX文件中的方法。这意味着单个DEX文件可被引用的方法总数被限制为65536。通常APK包含一个classes.dex文件,因此Android应用的方法总数不能超过这个数量,这包括Android框架、类库和你自己开发的代码。
 
这个问题可以通过将一个DEX文件分拆成多个DEX文件解决。Facebook介绍了为Android应用开发的Dalvik补丁;Android Developers博客介绍了通过自定义类加载过程的方法来解决此问题。但这些方法有些复杂而且并不优雅。
 
随着新的MultiDex支持库发布,Google正式为解决此问题提供官方支持。常州微信小程序开发构建超过65K方法数的应用介绍了如何使用Gradle构建多DEX应用。
 
首先使用Android SDK Manager升级到最新的Android SDK Build Tools和Android Support Library R21。然后进行以下两步操作:
 
 
1.修改Gradle配置文件,启用MultiDex并包含MultiDex支持:
 
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‘ } 
2.让应用支持多DEX文件。在MultiDexApplication JavaDoc中描述了三种可选方法:
 
在AndroidManifest.xml的application中声明android.support.multidex.MultiDexApplication;
如果你已经有自己的Application类,让其继承MultiDexApplication;
如果你的Application类已经继承自其它类,你不想/能修改它,那么可以重写attachBaseContext()方法:
@Override 
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base); MultiDex.install(this);
}
   使用MutiDex的主意事项
 
一. 如果你继承了MutiDexApplication或者覆写了Application中的attachBaseContext()方法.
 
Application类中逻辑的注意事项:
 
Application 中的静态全局变量会比MutiDex的 instal()方法优先加载,所以建议避免在Application类中使用静态变量引用main classes.dex文件以外dex文件中的类,可以根据如下所示的方式进行修改:
 
[java] view plain copy  技术分享技术分享
@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();  
    }  
 
二. 虽然Google解决了应用总方法数限制的问题,但并不意味着常州网站开发建设开发者可以任意扩大项目规模。Multidex仍有一些限制:
 
 
DEX文件安装到设备的过程非常复杂,如果第二个DEX文件太大,可能导致应用无响应。此时应该使用ProGuard减小DEX文件的大小。
由于Dalvik linearAlloc的Bug,应用可能无法在Android 4.0之前的版本启动,如果你的应用要支持这些版本就要多执行测试。
同样因为Dalvik linearAlloc的限制,如果请求大量内存可能导致崩溃。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中,系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时,会造成dexopt崩溃。
Multidex构建工具还不支持指定哪些类必须包含在首个DEX文件中,因此可能会导致某些类库(例如某个类库需要从原生代码访问Java代码)无法使用。
避免应用过大、方法过多仍然是Android开发者要注意的问题。Mihai Parparita的开源项目dex-method-counts可以用于统计APK中每个包的方法数量。
 
通常开发者自己的代码很难达到这样的方法数量限制,但随着第三方类库的加入,方法数就会迅速膨胀。因此选择合适的类库对Android开发者来说尤为重要。
 
开发者应该避免使用Google Guava这样的类库,它包含了13000多个方法。尽量使用专为移动应用设计的Lite/Android版本类库,或者使用小类库替换大类库,例如用Google-gson替换Jackson JSON。而对于Google Protocol Buffers这样的数据交换格式,其标准实现会自动生成大量的方法。采用Square Wire的实现则可以很好地解决游戏开发运营此问题。
 
 
常见问题
 
 
 
DexException: Library dex files are not supported in multi-dex mode,你可能会见到如下的错误:
 
 
[java] view plain copy  技术分享技术分享
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:
[java] view plain copy  技术分享技术分享
android {  
    // ...  
    dexOptions {  
        preDexLibraries = false  
    }  
}  
 
 
 
OutOfMemoryError: Java heap space
 
常州手游开发运行时如果看到如下错误:
[java] view plain copy  技术分享技术分享
UNEXPECTED TOP-LEVEL ERROR:  
java.lang.OutOfMemoryError: Java heap space  
 
在dexOptions中有一个字段用来增加java堆内存大小:
[java] view plain copy  技术分享技术分享
android {  
    // ...  
    dexOptions {  
        javaMaxHeapSize "2g"  
    }  
}      
          
 
使用eclipse的开发人员可以参考Google官方文档
 
https://developer.android.com/tools/building/multidex.html#mdex-gradle
 
需要安装支持gradle构建的插件,下载地址:
 
http://dist.springsource.com/release/TOOLS/gradle  (目前可能需要翻墙) 
 
 
 
 
 
参考相关资料:
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 plain copy  技术分享技术分享
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 plain copy  技术分享技术分享
dependencies {  
            compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])  
            compile project(‘:lib-project-module‘)  
        }  
技术分享
 
 
 
 
Android应用打破65K方法数

上篇:上一篇:Android中几种常用的按时器和延时方法
下篇:下一篇:--dex --num-threads=4 错误问题