十三、设置Multidex出现java.lang.NoClassDefFoundError

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

阅读更多

扫码向博主提问

WSoban

不畏浮云遮望眼,只缘身在最高层。
  • 擅长领域:
  • Android
去开通我的Chat快问
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30552993/article/details/75355492
文章标签: AS开发常见报错
个人分类: AS常见报错
所属专栏: AS常见报错
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭