需要分Dex的理由想必大家都知道了.正是在ART以前的Android系统中,Dex文件对于方法索引是用一个short类型的数据来存放的.而short的最大值是65535,因此当项目足够大包含方法数目足够多超过了65535(包括引用的外部Lib里面的所有方法),当运行App,就会得到如下的错误提示.

Unable to execute dex: method ID not in [, 0xffff]:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [, 0xffff]:

这个致命严重的Bug出现后,Android官方就写了一篇著名的Blog(这篇文章我读了五六遍,甚至连作者的Google+的照片我都看了两三次,我还是没有完全搞明白怎么Walkaround这个严重的问题).

再后来,慢慢发展,有很多能人异士发挥自己的创造力,写了开源的Lib放在GitHub上分享给其他Android开发者们使用.HelloMultiDex, Secondary-Dex-Gradle等等.

但是解铃还须系铃人,这种系统性的严重致命Bug,当然还是Android官方给出解决方案最让人放心.终于,我们还是等到了你,MultiDex Offical Solution.

我推荐官方文档这篇GitHub的文章一起看会有更好的了解,少走弯路.

下面说一说使用的步骤:

1. 修改Gradle,导入'com.android.support:multidex:1.0.0',打开multiDexEnabled;

android {
compileSdkVersion
buildToolsVersion "21.1.0" defaultConfig {
...
minSdkVersion
targetSdkVersion
... // Enabling multidex support.
multiDexEnabled true
}
...
} dependencies {
compile 'com.android.support:multidex:1.0.0'
}

2.修改Application.两种方法:

1) 直接把Application替换成MultiDexApplication

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.multidex.myapplication">
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
</manifest>

2) 在原来的Application中修改调用MultiDex.install(this);

public class HelloMultiDexApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
} @Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

到这里其实MultiDex的配置已经完成了.

但是,实际上下面介绍的3个问题也非常值得我们关注.

1. 一些在二级Dex加载之前,可能会被调用到的类(比如静态变量的类),需要放在主Dex中.否则会ClassNotFoundError.

通过修改Gradle,可以显式的把一些类放在Main Dex中.

afterEvaluate {
tasks.matching {
it.name.startsWith('dex')
}.each { dx ->
if (dx.additionalParameters == null) {
dx.additionalParameters = []
}
dx.additionalParameters += '--multi-dex'
dx.additionalParameters += "--main-dex-list=$projectDir/<filename>".toString()
}
}

上面是修改后的Gradle,其中<filename>是一个文本文件的文件名,存放在和这个Gradle脚本同一级的文件目录下.

而这个文本文件的内容如下.实际就是把需要放在Main Dex的类罗列出来.

android/support/multidex/BuildConfig/class
android/support/multidex/MultiDex$V14/class
android/support/multidex/MultiDex$V19/class
android/support/multidex/MultiDex$V4/class
android/support/multidex/MultiDex/class
android/support/multidex/MultiDexApplication/class
android/support/multidex/MultiDexExtractor$/class
android/support/multidex/MultiDexExtractor/class
android/support/multidex/ZipUtil$CentralDirectory/class
android/support/multidex/ZipUtil/class

2. 如果用使用其他Lib,要保证这些Lib没有被preDex,否则可能会抛出下面的异常

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:337)
at com.android.dx.command.dexer.Main.run(Main.java:243)
at com.android.dx.command.dexer.Main.main(Main.java:214)
at com.android.dx.command.Main.main(Main.java:106)

遇到这个异常,需要在Gradle中修改,让它不要对Lib做preDexing

android {
// ...
dexOptions {
preDexLibraries = false
}
}

3. 如果每次都打开MultiDex编译版本的话,会比平常用更多的时间(这个也容易理解,毕竟做了不少事情)

Android的官方文档也给了我们一个小小的建议,利用Gradle建立两个Flavor.一个minSdkVersion设置成21,这是用了ART支持的Dex格式,避免了MultiDex的开销.而另外一个Flavor就是原本支持的最小sdkVersion.平时开发时候调试程序,就用前者的Flavor,发布版本打包就用后者的Flavor.

android {
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion 14
}
}
...
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}

有了Android官方的支持后,MultiDex比最原始的解决方案简单多了.妈妈再也不用担心我们要分Dex啦!

Android 分Dex (MultiDex)的更多相关文章

  1. Android分包方案multidex

    对于功能越来越复杂的app的两大问题 问题一:当项目越来越大,方法数超过65536,编译时会出错(为什么是65536,参考下面关于dexopt对方法id检索存储介绍),这个所说的方法数包含用到的框架, ...

  2. Android兼容包multidex的开发和构建方法

    在Android开发中,函数方法超过65k限制后,我们就常常会用到multidex分包解决,但是multidex的配置,对系统apk的构建.签名.打包复杂性大大的增加,严重的降低了构建效率.那这个问题 ...

  3. IDA动态调试Android的DEX文件

    Android程序的dex文件的动态调试确实是个大问题,网上也有一些教程但是不是特别的详细,今天用到了IDA动态调试Android的DEX文件,特此记录一下. IDA 6.6新添加了对dex文件的调试 ...

  4. 通过源码看android系列之multidex库

    我们在开发项目时,喜欢引入好多的第三方包,大大的方便了我们的开发,但同时,因为android方法总数的限制,不能超过65k,然而呢,随着我们的开发,65k最终还是会超过,所以,google就给出了这个 ...

  5. 解决Android单个dex文件不能超过65535个方法问题

    一.找坑:谷歌规定单个dex文件中的方法不能超过65536的限制 我们编写项目过程中在工程的lib文件夹下引用的第三方插件jar包太多或者项目过大,编译运行时就有可能报出com.android.dex ...

  6. 是时候学习Android分屏开发了

    今年Google发布了Android N,Android N新增了不少功能,最受关注的自然就是分屏了. 这一功能对国内的很多手机用户并不陌生,其实很多第三方系统早已经实现了这一功能,如EMUI,Fly ...

  7. 解决Android单个dex文件不能超过65536个方法问题

    当我们的项目代码过大时,编译运行时会报Unable to execute dex: method ID not in[0, 0xffff]: 65536)错误.当出现这个错误时说明你本身自己的工程代码 ...

  8. Android分屏显示LogCat

    Eclipse里有非常多界面组件,文件列表.编辑区.类结构等等,在这么多界面组件里,再打开一个Logcat就基本没有什么空间了.与其挤在一起还不如分开成两个窗体. 或者你有两个屏幕,想一个屏幕编辑,一 ...

  9. Android分渠道打包(Python 3.4 实现)

    Android批量打包实现有很多方式你可以用Ant,Maven或者Gradle.在处理多个Library和NDK编译的时候配置有些麻烦,且每个渠道都编译一次效率较低.如果没有复杂的分渠道编译需求,我们 ...

随机推荐

  1. 20155339 《Java程序设计》实验五网络编程与安全实验报告

    20155339 <Java程序设计>实验五网络编程与安全实验报告 实验内容 实验一 1.两人一组结对编程: 参考http://www.cnblogs.com/rocedu/p/67667 ...

  2. day6 break continue for

    .for .break (整个while循环全部结束) )打印1-100的偶数.py )打印1-100的20个偶数.py )while嵌套中的break (就近原则) .continue 错误用法: ...

  3. Nginx入门篇(一)之Nginx介绍

    1.简介 Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 服务器. Nginx 是由 Igor Sysoe ...

  4. Docker入门篇(二)之docker的单主机网络

    Docker 安装时会自动在host上创建三个网络,我们可用 docker network ls命令查看: [root@localhost ~]# docker network ls NETWORK ...

  5. Html+CSS 学习第二天

    趁着这两天,将html和CSS基本上学了一遍,大家如果想学习的话,可以百度w3cSchool,进行学习. 基础我就不说了,直接将我做的一个登陆页面放上去.刚学完CSS,写个漂亮的登录界面恶心死我了,感 ...

  6. lua 中的 loadfile、dofile和require的调用

    文件 hello.lua print("hello") function say() print("hello world") end 1. 介绍: dofil ...

  7. 学习HTML 第二节.HTML头部

    HTML为什么要有个头部?还不太明白,可能是一些要提前声明的东西吧.先看看有什么内容吧. 可以添加在头部区域的元素标签为: <title>标题,这个我们知道了: <meta>使 ...

  8. 【Jmeter测试】使用Java请求进行Dubbo接口的测试

    如何构建一个Dubbo接口测试的通用框架(https://github.com/nitibu/jmeter-dubbo-test)​从上面的流程我们可以看出,测试类大致的一个结构: 使用json文件来 ...

  9. SQL中NULL的妙用

    商品表Products 库房表WarehouseDistrict 库存表WarehouseStock 一般写法 ;WITH stock AS ( SELECT DistrictId, ProductI ...

  10. python3【基础】-list&tuple

    一.list概述 list (列表)是python中最常用的数据类型之一,通过列表可以对数据实现最方便的存储,修改等操作.在python3中,list支持如下方法: Help on class lis ...