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方法数限制

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

Android Multidex 遇到的问题

Android 的classLoader在加载APK的时候限制了class.dex包含的Java方法总数不能超过65535,但是现在随便一个复杂一点的App,轻而易举就能超过65535。为了解决这个问...

MultiDex后java.lang.NoClassDefFoundError异常解决

出现java.lang.NoClassDefFoundError异常,排除掉classpath设置问题,发现是multidex后导致的。 为什么要用multidex?项目中因方法数超过了65536,...

Eclipse 引用外部library工程,运行时报NoClassDefFoundError的解决

好久没有碰过Eclipse了,公司这边现在在用这个做开发。 在将工程作为library引用至项目的过程中,运行时报错NoClassDefFoundError。 假设我现在是MultiDexApplic...

Android studio java.lang.NoClassDefFoundError: android.support.v4.app add multidex

序言 由于要兼容低版本所以AndroidStudio引入了v4包,但是引入的第三方包几乎都报异常java.lang.NoClassDefFoundError:下面是异常之一 08-11 09:35:...

从头认识java-12.6 接口与类型信息(怎么绕过接口直接调用类的所有方法)

这一章节我们来讨论一下接口与类型信息。在之前的章节里面我们提到接口,父类引用子类对象,然后把方法给缩窄了,但是我们这一章节学习到反射,这个约束就变得没有那么严格。我们来看看下面的例子:package ...

Android Studio自动生成带系统签名的apk

如果你需要开发一个带有系统权限的app,往往需要配置SharedUserId,比如: 此时,如果直接在AS中run,app是装不上的,需要先生成app,然后再使用系统文件对apk进行签名, j...

Sqoop2编译时出现java.lang.NoClassDefFoundError: org/sonatype/aether/graph/DependencyFilter

1.编译到docs的时候,出现下面的错误 java.lang.NoClassDefFoundError: org/sonatype/aether/graph/DependencyFilter ...

spring 配置xml连接数据库,出现 java.lang.NoClassDefFoundError: Lorg/apache/commons/pool/impl/GenericObjectPool

xml配置文件

Tomcat7.0启动时出现如下错误java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory

Tomcat7.0无法启动,报错 java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory at org.apach...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:AS开发中出现Error(十三)——设置Multidex出现java.lang.NoClassDefFoundError
举报原因:
原因补充:

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