【第22期】观点:IT 行业加班,到底有没有价值?

AS开发中出现Error(十三)——设置Multidex出现java.lang.NoClassDefFoundError

原创 2017年07月19日 11:38:03
java.lang.NoClassDefFoundError: org.chiki.base.utils.CommonUtils
at com.***.common.Common$Config.<clinit>(Common.java:32)
at com.***.app.APPContext.initDB(APPContext.java:66)
at com.***.app.APPContext.onCreate(APPContext.java:55)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4372)
at android.app.ActivityThread.access$1500(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5045)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)

一、出现场景
在Android6.0上编译没有问题,而在Android4.+上就出现了这种错误。

二、查找问题
看到这个错误的时候,有点懵了,NoClassDefFoundError(没有发现类错误),上面CommonUtils类是在Lib中的,如果说没有导入库的话,那就有点说不过去了吧。
通过检查build.gradle看到如下这句话:

android {
    ...
    defaultConfig {
        ...
        // 设置MultiDex可用
        multiDexEnabled true
    }
}

对此很好奇这是有什么用的呢?查阅了相关资料,原来是做编译class.dex分包用的。

然后我去解压了apk文件,发现解压出来的文件中包含有两个.dex文件:classes.dex和classes2.dex,再看java.lang.NoClassDefFoundError,结果显而易见,方法数超限了!

而我的项目中正是缺少了下面三步中的其中一步,然后报了错误。

三、解决方式:
这里可以分成四步:

1、 配置完整的build.gradle

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"
    // productFlavors是为了避免每次运行都把DEX重新加载一遍而设置的两套运行配置
    productFlavors {
        dev {
            minSdkVersion 21
        }
        prod {
            minSdkVersion 14
        }
    }
    ...
    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...
        // 设置MultiDex可用
        multiDexEnabled true
        //MultiDex手动拆包
        //multiDexKeepFile file ('multiDexKeep.txt')
        //multiDexKeepProguard file('multiDexKeep.pro')
    }
    // 保证其他的lib没有被preDex
    dexOptions {
        preDexLibraries = false
    }
}
dependencies {
    ...    
    // MultiDex的依赖
    compile 'com.android.support:multidex:1.0.1'
    ...
}

2、设置AndroidManifest.xml:引入自定义的MyApplication

 <application
        android:name=".MyApplication"
        ....>
</application>

3、设置MyApplication

public class MyApplication extends MultiDexApplication {

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

4、MultiDex手动拆包:如果上面三步可以了的话,这一步就可以省了。

Android Studio 中提供了相应的手动拆包的方法(可以任选其一),就是第一步中的那两个文件应放置于app->build.gradle同一个目录。
这里写图片描述

  • multiDexKeepFile:手动加入要放到Main.dex中的类。
android/support/multidex/MultiDex.class
  • multiDexKeepProguard:以Proguard的方式手动加入要放到Main.dex中的类。
-keep class android.support.multidex.** {*;}

四、MultiDex的产生背景:
随着时代的发展,现在的应用不断的添加了很多新的功能,酷炫的效果,引入第三方库也成了正常不过的事情,到达一定规模后就可能遇到方法数超限问题。

早期版本错误信息如下:

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

较新版本错误信息如下:

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

其中数字65536是关键,Android平台的Java虚拟机Dalvik执行Dex程序时,使用的是short类型来索引DEX文件中的方法。

这就意味着单个Dex文件可被引用的方法总数被限制为64x1024, 即65536。

因此当项目足够大包含方法数目足够多超过了65535(包括引用的外部Lib里面的所有方法),当运行App,就会得到超限错误提示。

为突破这个限制,需要使用multidex来生成多个dex文件,其中也有分主次

Android5.0 (API level 21)之前版本支持Multidex

Android5.0之前使用Dalvik运行时执行应用代码,默认Dalvik限制每个apk只能有一个字节码classed.dex文件。为突破这个限制,可以使用multidex support library来管理额外的dex文件(包括代码)。

Android5.0及更高版本支持Multidex

Android5.0及更高版本使用支持从apk中加载多个dex文件的ART运行时机制,在应用安装时,加载classed(…N).dex文件并编译成一个.oat文件以支持在Android设备上运行。关于Android 5.0运行时详见ART介绍。

Note: While using Instant Run, Android Studio automatically configures your app for multidex when your app’s minSdkVersion is set to 21 or higher. Because Instant Run only works with the debug version of your app, you still need to configure your release build for multidex to avoid the 64K limit.

如果使用Instant Run,当app的minSdkVersion大于或等于21时,Android Studio会自动配置支持multidex,但是仅debug版本有效,release版仍然需要配置multidex来突破64K限制。

看到这里你应该知道我的场景Android6.0可以,然后4.0不行的情况了吧。因为大于5.0自动配置支持了multidex。

借鉴:

更多配置方法数超过 64K 的应用
Android 分Dex (MultiDex)
Android应用使用Multidex突破64K方法数限制

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

AS开发中出现Error(二)——Java.lang.NoSuchFieldError: No static field xxx of type I in class Lcom/XX/R$id; or

错误:Java.lang.NoSuchFieldError: No static field xxx of type I in class Lcom/XX/R$id; or its superclas...

android中ADT版本问题: java.lang.NoClassDefFoundError和conversion to dalvik format failed with error 1错误

最近在ubuntu上面配置android开发环境时候出现n多错误,把心得说一下,如果遇到类似错误,修改下就好了,到目前为止,ADT的版本已经升级到18了。当SDK版本升级到4.0.3的时候,会要求ADT版本是17或者更高的版本,当升级以后,如果出现问题,有可能是JDK版本的问题,注意一下,ADT17...
  • mmdev
  • mmdev
  • 2012-05-09 23:42
  • 518

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

Eclipse使用过程中出现java.lang.NoClassDefFoundError的解决方案

<span class="tcnt" style="font-size: 20px; font-family:

eclipse开发Android项目时出现java.lang.NoClassDefFoundError的解决方法

一般是由于ADT版本问题导致的。 解决方法: 1.把Properties > Java Build Path > Libraries >下除了Android.X.x和android Depende...

tomcat:Error allocating a servlet instance --root cause: java.lang.NoClassDefFoundError

下午花了3小时来解决一个stupid问题: tomcat自带的例子运行良好,我自己写的一个servlet无论如何就是报下面的错误: Error allocating a servlet instance ... --root cause: java.lang.NoClassDefF...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)