AndroidStudio利用android-support-multidex解决65536问题(64k问题)

发生现象:关于64k的各种异常

当你的应用程序和库引用达到一定规模,通过USB安装软件不会报问题,但构建的时候错误显示你的应用已经达到了一个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的直接和间接的过度依赖关系:有时候我们用到某个Libaray的某几个方法或者功能时这个库非常大,减少这种依赖可能对与避免64k的问题非常有效。

● 在正式打包构建的时候,使用代码混淆器ProGuard混淆移除未使用的代码,也就是不把没有使用的代码打包到我们的apk中。

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

解决方法:64k问题

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

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

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

android {
    compileSdkVersion 25
    buildToolsVersion 

    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 25
        ...

        // 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);

重写了这个方法:

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后的构建优化

一、因此如果应用中包含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 25或者更高SDK版本。使用ART-supported格式生成multidex输出更快,为我们节省时间,所以我们不必在调试的使用也兼容到5.0以下,所以我们配置最低版本的时候做个如下兼容:

android {
    productFlavors {
        // 自定义偏好设置.
        dev {
            // 在Android leve 25或更高版本编译更快
            minSdkVersion 25
        }
        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'
    }
}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Android Studio实现轮播图的步骤: 1.在app/build.gradle文件中添加依赖项: ```gradle dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' implementation 'com.android.support:support-v4:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support:cardview-v7:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0' implementation 'com.android.support:palette-v7:28.0.0' implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:support-vector-drawable:28.0.0' implementation 'com.android.support:animated-vector-drawable:28.0.0' implementation 'com.android.support:customtabs:28.0.0' implementation 'com.android.support:exifinterface:28.0.0' implementation 'com.android.support:preference-v7:28.0.0' implementation 'com.android.support:preference-v14:28.0.0' implementation 'com.android.support:percent:28.0.0' implementation 'com.android.support:mediarouter-v7:28.0.0' implementation 'com.android.support:gridlayout-v7:28.0.0' implementation 'com.android.support:leanback-v17:28.0.0' implementation 'com.android.support:cursoradapter:28.0.0' implementation 'com.android.support:documentfile:28.0.0' implementation 'com.android.support:localbroadcastmanager:28.0.0' implementation 'com.android.support:print:28.0.0' implementation 'com.android.support:slices-builders:28.0.0' implementation 'com.android.support:slices-core:28.0.0' implementation 'com.android.support:slices-view:28.0.0' implementation 'com.android.support:wear:28.0.0' implementation 'com.android.support:wear-watchface:28.0.0' implementation 'com.android.support:wear-remote-interaction:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support:cardview-v7:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0' implementation 'com.android.support:palette-v7:28.0.0' implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:support-vector-drawable:28.0.0' implementation 'com.android.support:animated-vector-drawable:28.0.0' implementation 'com.android.support:customtabs:28.0.0' implementation 'com.android.support:exifinterface:28.0.0' implementation 'com.android.support:preference-v7:28.0.0' implementation 'com.android.support:preference-v14:28.0.0' implementation 'com.android.support:percent:28.0.0' implementation 'com.android.support:mediarouter-v7:28.0.0' implementation 'com.android.support:gridlayout-v7:28.0.0' implementation 'com.android.support:leanback-v17:28.0.0' implementation 'com.android.support:cursoradapter:28.0.0' implementation 'com.android.support:documentfile:28.0.0' implementation 'com.android.support:localbroadcastmanager:28.0.0' implementation 'com.android.support:print:28.0.0' implementation 'com.android.support:slices-builders:28.0.0' implementation 'com.android.support:slices-core:28.0.0' implementation 'com.android.support:slices-view:28.0.0' implementation 'com.android.support:wear:28.0.0' implementation 'com.android.support:wear-watchface:28.0.0' implementation 'com.android.support:wear-remote-interaction:28.0.0' implementation 'com.youth.banner:banner:1.4.10' } ``` 2.在布局文件中添加Banner组件: ```xml <com.youth.banner.Banner android:id="@+id/banner" android:layout_width="match_parent" android:layout_height="200dp" app:banner_indicatorGravity="center" app:banner_delay_time="3000" app:banner_is_auto_play="true" app:banner_scroll_time="1000" /> ``` 3.在Activity或Fragment中设置Banner的数据源和图片加载器: ```java // 设置数据源 List<String> images = new ArrayList<>(); images.add("http://img.zcool.cn/community/01c8dc5d6f1e6fa801219c77f8f8c9.jpg"); images.add("http://img.zcool.cn/community/01c8dc5d6f1e6fa801219c77f8f8c9.jpg"); images.add("http://img.zcool.cn/community/01c8dc5d6f1e6fa801219c77f8f8c9.jpg"); banner.setImages(images); // 设置图片加载器 banner.setImageLoader(new GlideImageLoader()); ``` 4.创建图片加载器类: ```java public class GlideImageLoader extends ImageLoader { @Override public void displayImage(Context context, Object path, ImageView imageView) { Glide.with(context).load(path).into(imageView); } } ``` 5.启动Banner轮播: ```java banner.start(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值