Java MultiDex NoClassDefFound 错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26655541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:00:50  来源:igfitidea点击:

MultiDex NoClassDefFound error

javaandroid

提问by 4emodan

I have converted my application into MultiDex to bear with 64k dex limit. Now it looks like this:

我已将我的应用程序转换为 MultiDex 以承受 64k dex 的限制。现在它看起来像这样:

public class App extends MultiDexApplication {

private AppWrapper instance;

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

@Override
public void onCreate() {
    super.onCreate();

    if (instance == null) {
        instance = new AppWrapper(this);
    }
}
}

I've pulled all the usual logic from App to AppWidgetto make MultiDexwork. And it works ok on other teammates' computers. But not with me. It keeps throwing java.lang.NoClassDefFoundErroron application create:

我已经从 App 中提取了所有通常的逻辑AppWidget来进行MultiDex工作。它在其他队友的电脑上运行正常。但不是和我在一起。它不断抛出java.lang.NoClassDefFoundError应用程序创建:

I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed
I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed
E/dalvikvm﹕ Could not find class     'com.playday.app.core.AppWrapper', referenced from method com.playday.app.core.App.onCreate
W/dalvikvm﹕ VFY: unable to resolve     new-instance 7076 (Lcom/playday/app/core/AppWrapper;) in Lcom/playday/app/core/App;
D/dalvikvm﹕ VFY: replacing opcode     0x22 at 0x0007
I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed
D/dalvikvm﹕ DexOpt: unable to opt     direct call 0xc21b at 0x09 in Lcom/playday/app/core/App;.onCreate
I/MultiDex﹕ VM with version 1.6.0     does not have multidex support
I/MultiDex﹕ install
I/MultiDex﹕ MultiDexExtractor.load(    /data/app/com.playdayteam.playday.debug-1.apk, false)
I/MultiDex﹕ Detected that     extraction must be performed.
I/MultiDex﹕ Trying to delete old     file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.    debug-2.apk.classes2.dex of size 1484912
I/MultiDex﹕ Deleted old file     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-2    .apk.classes2.dex
I/MultiDex﹕ Trying to delete old     file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.    debug-2.apk.classes2.zip of size 540964
I/MultiDex﹕ Deleted old file     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-2    .apk.classes2.zip
D/dalvikvm﹕ GC_CONCURRENT freed     186K, 11% free 3245K/3640K, paused 2ms+4ms, total 28ms
D/dalvikvm﹕ WAIT_FOR_CONCURRENT_GC     blocked 5ms
D/dalvikvm﹕ GC_CONCURRENT freed     156K, 8% free 3593K/3904K, paused 3ms+2ms, total 22ms
I/MultiDex﹕ Extraction is needed     for file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.    playday.debug-1.apk.classes2.zip
I/MultiDex﹕ Extracting     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1    .apk.classes576886388.zip
I/MultiDex﹕ Renaming to     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1    .apk.classes2.zip
I/MultiDex﹕ Extraction success -     length /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.    debug-1.apk.classes2.zip: 540964
I/MultiDex﹕ load found 1 secondary     dex files
D/dalvikvm﹕ DexOpt: --- BEGIN 'com.    playdayteam.playday.debug-1.apk.classes2.zip' (bootstrap=0) ---
D/dalvikvm﹕ DexOpt: --- END 'com.    playdayteam.playday.debug-1.apk.classes2.zip' (success) ---
D/dalvikvm﹕ DEX prep '/data/data/com    .playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1.apk.classes2.    zip': unzip in 28ms, rewrite 387ms
I/MultiDex﹕ install done
I/MultiDex﹕ install
D/AndroidRuntime﹕ Shutting down VM
W/dalvikvm﹕ threadid=1: thread     exiting with uncaught exception (group=0x41c1d930)
E/AndroidRuntime﹕ FATAL EXCEPTION:     main
    java.lang.NoClassDefFoundError: com.playday.app.core.AppWrapper
            at com.playday.app.core.App.onCreate(App.java:22)
            at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1006)
            at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4457)
            at android.app.ActivityThread.access00(ActivityThread.java:142)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1332)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5105)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)    

I have the same Android Studio, gradle, sdk, jdk versions, same code. I've even tried to format hard drive and reinstall OS to make sure that environment is the same. What can be the cause of this strange problem?

我有相同的 Android Studio、gradle、sdk、jdk 版本,相同的代码。我什至尝试过格式化硬盘并重新安装操作系统以确保环境相同。这个奇怪问题的原因是什么?

This is my build.gradle:

这是我的build.gradle

apply plugin: 'com.android.application'

repositories {
    maven { url 'http://dl.bintray.com/populov/maven' }
    mavenCentral()
    maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}

android {
    compileSdkVersion project.api_level
    buildToolsVersion project.build_tools_version

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion project.api_level
    }

    sourceSets {
        instrumentTest.setRoot('src/test')
    }

    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/ASL2.0'
        exclude 'AndroidManifest.xml'
    }

    defaultConfig {
        versionName "0.3.2"
        versionCode 23
    }

    buildTypes {

        debug {
            debuggable true
            applicationIdSuffix ".debug"
        }

        beta {
            debuggable true
            signingConfig signingConfigs.release
            applicationIdSuffix ".beta"
        }

        release {
            signingConfig signingConfigs.release
            runProguard false
            proguardFile file('proguard-rules.txt')
            proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
        }
    }

    dexOptions {
        incremental false
        preDexLibraries false
    }
}

dependencies {
    compile "com.android.support:support-v13:$project.support_lib_version"
    compile "com.android.support:support-v4:$project.support_lib_version"
    compile "com.android.support:appcompat-v7:$project.support_lib_version"
    compile 'com.google.android.gms:play-services:6.1.11'
    compile('de.keyboardsurfer.android.widget:crouton:1.8.5@aar') {
        exclude group: 'com.google.android', module: 'support-v4'
    }
    compile('com.octo.android.robospice:robospice:1.4.14'){
        exclude group: 'commons-io', module: 'commons-io'
    }
    compile('com.octo.android.robospice:robospice-retrofit:1.4.14'){
        exclude group: 'commons-io', module: 'commons-io'
    }
    compile 'com.squareup.retrofit:retrofit:1.6.1'
    compile 'com.google.code.gson:gson:2.3'
    compile 'com.viewpagerindicator:library:2.4.1@aar'
    compile 'com.squareup.picasso:picasso:2.3.3'
    compile 'com.squareup.okhttp:okhttp:2.0.0'
    compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'

    compile 'com.etsy.android.grid:library:1.0.5'
    compile 'com.squareup:otto:1.3.4'
    compile 'com.darwinsys:hirondelle-date4j:1.5.1'
    compile 'com.github.chrisbanes.photoview:library:1.2.3'
    compile 'me.grantland:autofittextview:0.2.0'
    compile 'it.sephiroth.android.library.horizontallistview:library:1.2.1'
    compile 'org.ocpsoft.prettytime:prettytime:3.2.4.Final'
    compile 'com.google.guava:guava:18.0'
    compile 'com.github.castorflex.smoothprogressbar:library:0.5.2'
    compile 'com.makeramen:roundedimageview:1.3.0'
    compile 'org.lucasr.twowayview:twowayview:0.1.1'
    compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'

    compile project(':libs:LoopingViewPager')
    compile project(':libs:PhotoView-2.2.1')
    compile files('libs/localytics.jar')
    compile files('libs/android-support-multidex.jar')

    compile 'net.hockeyapp.android:HockeySDK:3.0.2'
}

afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = []
        }
        dx.additionalParameters += '--multi-dex' // enable multidex
        dx.additionalParameters += "--main-dex-list=$projectDir/multidex.keep".toString()
    }
}

Update. My multidex.keepfile:

更新。我的multidex.keep文件:

android/support/multidex/BuildConfig.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/MultiDex$V4.class
android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/ZipUtil$CentralDirectory.class
android/support/multidex/ZipUtil.class
com/playday/app/models/notification/Badge.class
com/playday/app/models/User.class
com/playday/app/core/AppWrapper.class
com/playday/app/core/App.class

采纳答案by Alex Lipov

Your AppWrapperclass fails to load because the retrofit.ErrorHandlerinterface is not included in main dex file.

AppWrapper因为类加载失败retrofit.ErrorHandler接口不在主DEX文件包括在内。

How do you calculate which classes to put in your main-dex-list file?
There's a scriptthat can generate it for you. I wrote a blogpostthat shows how to use it.

您如何计算将哪些类放入 main-dex-list 文件中?
有一个脚本可以为您生成它。我写了一篇博文,展示了如何使用它。

Update (10/31/2014):
Gradle plugin v0.14.0 now does it automatically. See my answer here.

更新 (10/31/2014)
Gradle 插件 v0.14.0 现在自动执行。在这里看到我的答案。

Update (24/04/2017):
The developer guideexplains how to pick specific classes with a gradle option if it doesn't pick all the right ones automatically.

更新(24/04/2017)
开发人员指南解释了如何选择具体的班级,选择的gradle如果它不自动拾取所有正确的。

回答by 4emodan

I've finally solved it! Cause was not in the onCreate()method. There was this line from logcat that gained my attention:

我终于解决了!原因不在onCreate()方法中。logcat 的这一行引起了我的注意:

I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed

This line fired before all the MultiDex log. Source of the problem was Retrofit ErrorHandlerinterface, which AppWrapperimplements.

此行在所有 MultiDex 日志之前触发。问题的根源是 RetrofitErrorHandler接口,它AppWrapper实现了。

As @AlexLipov said in his answer, Dalvik just couldn't find ErrorHandlerclass and failed to load AppWrapper.

正如@AlexLipov 在他的回答中所说,Dalvik 只是找不到ErrorHandlerclass 并且无法加载AppWrapper.

Anyway, solution is not to implement ErrorHandlerdirectly by AppWrapperand pull it into private variable instead.

无论如何,解决方案不是ErrorHandler直接实现AppWrapper并将其拉入私有变量。

回答by PaulR

If you're extending the MultiDexApplication you don't need to make the MultiDex.install(context) call as it's already happening (see source link). If you need to use attachBaseContext then just make sure to call super.attachBaseContext(context).

如果您要扩展 MultiDexApplication,则不需要进行 MultiDex.install(context) 调用,因为它已经发生了(请参阅源链接)。如果您需要使用 attachBaseContext 那么只需确保调用 super.attachBaseContext(context)。

https://android.googlesource.com/platform/frameworks/multidex/+/1bb1ab007f6b9405227ea4ce07d2061e4dbb6fe0/library/src/android/support/multidex/MultiDexApplication.java

https://android.googlesource.com/platform/frameworks/multidex/+/1bb1ab007f6b9405227ea4ce07d2061e4dbb6fe0/library/src/android/support/multidex/MultiDexApplication.java

We just updated developers.android.com with instructions on how to use the support library with the Android gradle plugin including an development optimization for quick development build cycle times.

我们刚刚更新了 developer.android.com,其中包含有关如何将支持库与 Android gradle 插件配合使用的说明,包括针对快速开发构建周期的开发优化。

https://developer.android.com/tools/building/multidex.html

https://developer.android.com/tools/building/multidex.html

回答by Thomas Sunderland

If anyone gets here because their Application class is not being found on pre-Lollipop devices, but the app runs fine on Lollipop and above then this appears to be a known issue with Hyman and Multidex.

如果有人因为在 Lollipop 之前的设备上找不到他们的 Application 类而来到这里,但该应用程序在 Lollipop 及更高版本上运行良好,那么这似乎是 Hyman 和 Multidex 的一个已知问题。

Ref: Hyman Issue 213484

参考:Hyman问题 213484

Ref: Hyman Issue 224026

参考:Hyman问题 224026

回答by singh.indolia

I also got this kind of problem. Solution in my case was: In my build.gradle file, there were multiple entries of compile 'com.android.support:multidex:1.0.0'in dependencies. like:

我也遇到了这样的问题。我的解决方案是:在我的 build.gradle 文件中,有多个compile 'com.android.support:multidex:1.0.0'依赖项。喜欢:

dependencies {    
compile 'com.android.support:multidex:1.0.0'
compile 'com.android.support:multidex:1.0.0'
// other dependencies ........
}

just put only one compile 'com.android.support:multidex:1.0.0' like:

只放一个编译 'com.android.support:multidex:1.0.0' 像:

dependencies {    
compile 'com.android.support:multidex:1.0.0'
// other dependencies ........
}

回答by Dhiraj Gupta

The NoClassDefFoundcan happen with any arbitrary class that did not load up on a device with API earlier than Lollipop and with multidex enabled. If you set up ProGuard properly then you can easily get by without having the MultiDex overhead making your app slow to launch for your releasebuilds, especially on old devices. However, you don't want ProGuard slowing you down while you develop your app in debug mode. If you try to launch your debug build with ProGuard disabled, you will start to get build errors like com.android.dex.DexIndexOverflowException: Cannot merge new index 72118 into a non-jumbo instruction!

NoClassDefFound可以与没有在设备上与API装载比棒棒糖和启用multidex前面任意类发生。如果您正确设置了 ProGuard,那么您就可以轻松度过难关,而不会因为 MultiDex 开销而使您的应用程序在发布版本时启动缓慢,尤其是在旧设备上。但是,当您在调试模式下开发应用程序时,您不希望 ProGuard 减慢您的速度。如果您尝试在禁用 ProGuard 的情况下启动调试构建,您将开始收到构建错误,例如com.android.dex.DexIndexOverflowException: Cannot merge new index 72118 into a non-jumbo instruction!

So what you reallywant is ProGuard enabled and multidex disabled only on release builds, while debug builds should be the opposite with Proguard disabled and multidex enabled. You also have to be picky and use less dependencies, of course, because your release build willbe subject to the 64K limit.

因此,您真正想要的是仅在发布版本中启用 ProGuard 和禁用 multidex,而调试版本应该与禁用 Proguard 和启用 multidex 的情况相反。当然,您还必须挑剔并使用较少的依赖项,因为您的发布版本受到 64K 的限制。

This requires setting up build.gradle to have buildTypesconfigs, and compiling the multidex support library dependency only for debug.

这需要将 build.gradle 设置为具有buildTypes配置,并编译 multidex 支持库依赖项仅用于调试。

The Application subclass must also be set to derive from a different subclass depending on whether you're in multidex mode or not. This can be achieved using the gradle manifest merger principle, by defining an override manifest for your debug build, and then specifying your Application class differently.

Application 子类还必须设置为派生自不同的子类,具体取决于您是否处于多索引模式。这可以使用 gradle 清单合并原则来实现,方法是为您的调试版本定义一个覆盖清单,然后以不同的方式指定您的应用程序类。

Here's the relevant app module build.gradle:

这是相关的应用模块 build.gradle:

android {
...
    buildTypes {
        debug {
            minifyEnabled false //Disabled Proguard
            multiDexEnabled true // Enabling multi-dex support.
        }
        release {
            minifyEnabled true //Enabled Proguard
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            multiDexEnabled false // Disable multi-dex support.
        }
    }
    dependencies {
        debugCompile 'com.android.support:multidex:1.0.1' //debugCompile makes it included only for debug builds
        ...
    }
}

If you don't use an Application subclass, then all you need to do is specify the name of the Application subclass android.support.multidex.MultiDexApplicationas noted in https://developer.android.com/studio/build/multidex.htmlbut you want to do this onlyfor your debug build.

如果您不使用 Application 子类,那么您需要做的就是指定 Application 子类的名称,android.support.multidex.MultiDexApplicationhttps://developer.android.com/studio/build/multidex.html 中所述,但您想这样做适用于您的调试版本。

For this, you have to specify overriding files in the debug and release variant folder hierarchy, like so:

为此,您必须在调试和发布变体文件夹层次结构中指定覆盖文件,如下所示:

src
    - main
        - AndroidManifest.xml
        - java/com/yourcompany/MyApplication.java (extends from BaseApplication)
    - release
        - java/com/yourcompany/BaseApplication.java (extends from Application)
    - debug
        - AndroidManifest.xml
        - java/com/yourcompany/BaseApplication.java (extends from MultiDexApplication)

Yes, you create debugand releasefolders next to your main module's folder. Add the following files within:

是的,您可以创建debugrelease文件夹旁边的主模块的文件夹。在其中添加以下文件:

debug/AndroidManifest.xml

调试/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >
    <application
        android:name="com.yourcompany.MyApplication"
        tools:replace="android:name"/>
</manifest>

This manifest will only be included in debug builds, and will be ignored for your release one.

此清单将仅包含在调试版本中,并且在您的第一个版本中将被忽略。

release/java/com/yourcompany/BaseApplication.java

发布/java/com/yourcompany/BaseApplication.java

public class BaseApplication extends Application {
}

debug/java/com/yourcompany/BaseApplication.java

调试/java/com/yourcompany/BaseApplication.java

public class BaseApplication extends MultiDexApplication {
}            

main/java/com/yourcompany/MyApplication.java

main/java/com/yourcompany/MyApplication.java

public class MyApplication extends BaseApplication {
    @Override
    public void onCreate() {
        super.onCreate();
        //Init database, etc. etc.;
    }
}            

In this way, you can add your App's functionality into MyApplication.javawhile having differing base classes.

通过这种方式,您可以MyApplication.java在具有不同基类的同时添加应用程序的功能。

回答by dvrm

if everything looks OK, but this error appears,

如果一切正常,但出现此错误,

try to disable instant run!!!

尝试禁用即时运行!!!

when I disabled it all the classes were loaded properly.

当我禁用它时,所有类都被正确加载。

回答by Daniel S.

I tried with a lot of solutions a no one worked for me. Finally, I found this:

我尝试了很多解决方案,但没有人为我工作。最后,我发现了这个:

    public class MyApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

And was the only solution for my problem. Maybe someone is having the same problem and this could help :)

并且是我问题的唯一解决方案。也许有人遇到了同样的问题,这可能会有所帮助:)