AndroidStudio利用android-support-multidex解决64k的各种异常

64k的各种异常

当你的应用程序和库引用达到一定规模,你遇到构建错误显示你的应用已经达到了一个Android应用程序构建体系结构的限制。早期版本的构建系统报告这个错误如下:

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

或者

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)

最新版本的Android构建系统显示一个不同的错误,但是是同样一个问题:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

或者

Error:The number of method references in a .dex file cannot exceed 64K.

上面的错误显示一个共同的数字:65536。这个数字是重要的,它代表了引用的总数,可以在单个调用的代码Dalvik可执行(Dex)字节码文件。如果你的Android应用发生这个错误,恭喜你,你的代码已经达到了一定的量!本文解释了如何解决这个限制并继续构建应用程序。

关于64 k引用限制

Android应用程序(APK)在Dalvik可执行文件的形式包含可执行的字节码文件(DEX)文件,其中包含已编译的代码来运行你的应用程序。Dalvik可执行规格限制一个Dex文件包含65536个方法:包括Android框架方法、Library方法的总数、和你自己的代码方法总数。因为65536等于64×1024,这一限制被称为“64k引用限制”。
这个极限就要求我们配置应用程序的构建过程,需要生成多个DEX文件,所以称为multidex 配置。

分析原因与注意事项

解决方法分Android 5.0及以上系统和5.0以下系统怎么做。客官们不要着急,先看我一个个分析原因,毕竟我要装下逼哈哈。

一、Android 5.0以下的版本

Android 5.0(API leve 21)之前的系统使用Dalvik执行应用程序代码。默认情况下,Dalvik限制一个apk只有一个Dex文件。为了绕过这个限制, 我们可以使用multidex support library,它成为我们APK的主要DEX文件的一部分,负责管理我们APK访问其他DEX文件和代码。

注意: 如果咱的项目minSdkVersion是20或更低,运行到Android 4.4(API leve 20)或者更低版本的设备上时需要禁用AndroidStudio的即时运行

二、Android 5.0和更高版本

Android 5.0(API leve 21)和更高的系统使用runtime是ART ,原生支持从应用的apk文件加载多个DEX文件。ART在安装应用时预编译应用程序,会扫描多个classes(..N).dex文件编译成一个.oat的文件。更多Android5.0 runtime的更多信息,请参见即时运行-instant-run。

注意: 如果你使用即时运行 , AndroidStudio自动配置你的应用程序,你应用程序的minSdkVersion应该设置为21或更高。因为即时只工作在你APP的Debug版本,你任然需要配置你的release版本构建时用multidex避免64k的限制。

尽量避免64k限制

在配置我们的App启用64k或者更多方法引用之前,我们可以减少应用代码内的调度总数,包括我们自身应用的方法和第三方的库,下面的几个策略或许可以帮到你:

•检查你的APP的直接和间接的过度依赖关系:有时候我们用到某个Libaray的某几个方法或者功能时这个库非常大,减少这种依赖可能对与避免64k的问题非常有效。
•在正式打包构建的时候,使用代码混淆器ProGuard混淆移除未使用的代码,也就是不把没有使用的代码打包到我们的apk中。

使用上面的方法可以帮助我们避免在应用程序中生成太多无用的方法和减小我们apk的大小,这对于用自己服务器做app更新升级的同学是非常有帮助的。

这里给大家推荐下任玉刚同学的插件式开发框架:https://github.com/singwhatiwanna/dynamic-load-apk,共同参与开发者:田啸,宋思宇。

解决64k问题

在Android SDK Build Tools 21.1或者更高版本的build工具中用Android plugin gradle。确保你更新Android SDK build tools和Android support到最新版本,然后用multidex配置应用程序。我们必须要做两步。

第一步,修改主module的build.gradle文件

在gradle中依赖multidex,并启用multiDexEnable:

android {
 compileSdkVersion 21
 buildToolsVersion 

 defaultConfig {
  ...
  minSdkVersion 14
  targetSdkVersion 21
  ...

  // Enabling multidex support.
  multiDexEnabled true
 }
 ...
}

dependencies {
 compile 'com.android.support:multidex:1.0.1'
}

第二步,继承android.support.multidex.MultiDexApplication类

两种情况

第一种情况,如果我们的APP没有重写过Application类,我们直接继承MultiDexApplication,然后在manifest.xml中注册Application即可。

第二种情况,如果我们已经重写过Application类,重写attachBaseContext(Context)方法,并调用MultiDex.install(this);即可:

protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);

因为我翻过MultiDexApplication的源码了,里面就是重写了这个方法而已哈哈:

public class MultiDexApplication extends Application {
 public MultiDexApplication() {
 }

 protected void attachBaseContext(Context base) {
  super.attachBaseContext(base);
  MultiDex.install(this);
 }
}

注册Application

<?xml version= encoding=?>
<manifest xmlns:android=
 package=>
 <application
  ...
  android:name="刚才重写的Application全类名">
  ...
 </application>
</manifest>

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代码)无法使用。

使用了multidex后的构建优化

一、因此如果应用中包含lirary工程,可能会发生如下错误:

UNEXPECTED TOP-LEVEL EXCEPTION: 
com.android.dex.DexException: Library dex files are not supported in multi-dex mode

这个时候我们需要禁用预编译:

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

 二、如果在运行的时候遇到如下错误:

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

我们需要加大java堆内存大小:

maxProcessCount 4 // this is the default value
javaMaxHeapSize "2g"

三、提升运行速度

在Android leve 21或者更高SDK版本。使用ART-supported格式生成multidex输出更快,为我们节省时间,所以我们不必在调试的使用也兼容到5.0以下,所以我们配置最低版本的时候做个如下兼容:

android {
 productFlavors {
  // 自定义偏好设置.
  dev {
   // 在Android leve 21或更高版本编译更快
   minSdkVersion 21
  }
  prod {
   // 真正的生产环境.
   minSdkVersion 14
  }
 }
 ...
}
dependencies {
 compile 'com.android.support:multidex:1.0.1'
}

Android plugin Gradle版本低于1.1怎么办

你需要添加 以下依赖 multidex-instrumentation :

dependencies {
 androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') {
   exclude group: 'com.android.support', module: 'multidex'
 }
}

Eclipse Jar包下载:http://xiazai.jb51.net/201609/yuanma/androidsupportmultidex(jb51.net).rar

官方参考文档:https://developer.android.com/tools/building/multidex.html

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android分包MultiDex策略详解

    1.分包背景 这里首先介绍下MultiDex的产生背景. 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的.这个过程会生成一个ODEX文件,即Optimised Dex.执行ODex的效率会比直接执行Dex文件的效率要高很多. 但是在早期的Android系统中,DexOpt有一个问题,DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面.但是这个链表的长度是用一

  • AndroidStudio利用android-support-multidex解决64k的各种异常

    64k的各种异常 当你的应用程序和库引用达到一定规模,你遇到构建错误显示你的应用已经达到了一个Android应用程序构建体系结构的限制.早期版本的构建系统报告这个错误如下: Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536 或者 UNEXPECTED TOP-LEVEL EXCEPTION:  java.lang.IllegalArgumentExcepti

  • 解决android.support.v4.content.FileProvide找不到的问题

    在AndroidManifest.xml中加入下面这段话后, <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.boxin.forklift.fileprovider" android:exported="false" android:grantUriPermissions="true">

  • 解决java.lang.NoClassDefFoundError: android.support.v4.animation.AnimatorCompatHelper问题

    在开发过程中,有的时候引入了多个三方库.在调用的时候会出现版本对应不上的原因.就会出现如标题的异常.解决的办法就是在你的build.gradle里面加入如下代码块: configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> def requested = details.requested if (requested.group == 'com.android.supp

  • Android添加glide库报错Error: Failed to resolve: com.android.support:support-annotations:26.0.2的解决

    前言 Glide是 Google推荐的图片加载库,它可以支持来自url,Android资源,文件,Uri中的图片加载,同时还支持gif图片的加载,以及各种图片显示前的bitmap处理(例如:圆角图片,圆形图片,高斯模糊,旋转,灰度等等),缓存处理,请求优先级处理,动画处理,缩略图处理,图片大小自定义等等.可谓是非常的强大. 在Glide的使用方面,它和Picasso的使用方法是比较相似的,并且他们的运行机制也有很多相似的地方,很多博文会把二者进行比较,此文也采取一样的方式,通过比较二者来学习他们

  • com.android.support版本冲突解决方法

    项目中不同Module的support包版本冲突怎么办? 只需要将以下代码复制到每个模块的build.gradle(Module:xxx)文件的根目录即可: // 统一当前Module的所有support包版本 configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> def requested = details.requested if (requested.gro

  • Android 有效的解决内存泄漏的问题实例详解

    Android 有效的解决内存泄漏的问题 Android内存泄漏,我想做Android 应用的时候遇到的话很是头疼,这里是我在网上找的不错的资料,实例详解这个问题的解决方案 前言:最近在研究Handler的知识,其中涉及到一个问题,如何避免Handler带来的内存溢出问题.在网上找了很多资料,有很多都是互相抄的,没有实际的作用. 本文的内存泄漏检测工具是:LeakCanary  github地址:https://github.com/square/leakcanary 什么是内存泄漏? 内存泄漏

  • Android XmlResourceParser出错解决办法

    Android XmlResourceParser出错解决办法 今天有点懵逼,对接的pos机在debug模式下安装在手机上是木有报错的,然后打包出来就出错了. 然后看厂商的demo发现也是这样,我特么就感觉是没有代码混淆的问题,然后代码混了下果断ok. 错误如下: java.lang.NoSuchMethodError: No interface method i()I in class Landroid/content/res/XmlResourceParser; or its super c

  • Android Support Palette使用详解

    使用Palette API选择颜色 良好的视觉设计是app成功所必不可少的, 而色彩设计体系是设计的基础构成. Palette包是支持包, 能够从图片中解析出突出的颜色, 从而帮助你创建出视觉迷人的应用 你能够使用Palette包设计布局主题, 并把自定义色彩应用到可视化元素中. 比如, 你可以根据专辑封面, 用Palette创建为歌曲创建一个彩色标题卡片, 或者当应用背景图片发生改变时调整toolbar颜色. Palette对象给予你权限访问Bitmap图片里面的颜色, 同时也根据Bitmap

  • 利用Android设计一个倒计时组件

    目录 1 背景 2 对比分析 2.1 是否是倒计时 2.2 支持多任务 2.3 支持时间校准 2.4 支持同帧刷新 2.5 支持延迟执行 2.6 支持CPU休眠 3 需求目标 4 设计类结构 5 具体实现 5.1 收口 5.2 支持与RxJava协同 5.3 支持时间校准 5.4 支持同步刷新 5.5 支持延迟执行 1 背景 我们在项目中经常有倒计时的场景,比如活动倒计时.抢红包倒计时等等.通常情况下,我们实现倒计时的方案有Android中的CountDownTimer.Java中自带的Time

随机推荐