Too many classes in --main-dex-list, main dex capacity exceeded | 主Dex引用太多怎么办?

来源:互联网 发布:微软云计算平台包含 编辑:程序博客网 时间:2024/05/29 09:03

主 dex 里面会有 Application、Activity、Service、Receiver、Provider、Instrumentation、BackupAgent 和 Annotation。当这些类以及直接引用类比较多的时候,都要塞进主 dex ,就会引发 main dex capacity exceeded build error 。

在Lollipop之前的设备上,主Dex仅仅被Framework加载。为了支持multi-dex,应用必须明确的让类加载器去加载二级Dex文件(这就是为什么要调用MultiDex#install)

那就是说应用的主Dex应该包含所有的即将被加载器访问的类,如果你的应用的代码试着在类加载器加载之前,去引用二级Dex里面的class就会抛出Class Not Found异常。

那什么样的类会被包含在主Dex里面?

会有三个顺序执行的任务将会决定哪个类应该被包含在主Dex里。

  1. collect{variant}MultiDexComponents task,这个任务会根据manifest把所有应用组件(application, activities, services, receivers, providers)的名字写到一个文本文件。因此,如果你没有把其中的组件注册到manifest,那就不会被包含到主Dex里,也会有一些不注册的class也会被包含进去,比如注解。查看下CreateManifestKeepList.groovy 的源码就可以看到完整的包含列表。这个任务输出的文件是 manifest_keep.txt,路径为:app/build/intermediates/multi-dex。
  2. shrink{variant}MultiDexComponents task,这个任务会掉起ProGuard程序创建一个压缩过的Jar文件,这个文件里只包含manifest_keep.txt里的class,这个任务输出的文件是componentClasses.jar
  3. create{variant}MainDexClassList task,这个任务会解析componentClasses.jar文件,为每一个类文件计算直接的引用层级,具体实现请查看链接。因此,如果你应用有一个注册的组件包含类X的变量,类X也会被包含进主Dex里面。这个任务输出的文件为:maindexlist.txt,包含主Dex里面所有的类。

如果最低版本是21会发生什么?
如果最低版本是21上面所有的任务都不会执行,也不会有主Dex列表的计算。这是因为在应用安装期间所有的dex文件都会被ART转换为一个.oat文件。

所以如果这些类的引用超过了65536,构建的时候就会抛出这个Too many classes in --main-dex-list, main dex capacity exceeded 错误

那到底解决方案是什么?
升级Gradle plugin的版本到2.2.0-alpha4以上,例:classpath 'com.android.tools.build:gradle:2.2.0',可以查看关于这个问题的Google Issue Tracker

参考:Too many classes in –main-dex-list, main dex capacity exceeded

原创粉丝点击