简体   繁体   中英

MultiDex NoClassDefFound error

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

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 AppWidget to make MultiDex work. And it works ok on other teammates' computers. But not with me. It keeps throwing java.lang.NoClassDefFoundError on application create:

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.access$1300(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?

This is my 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.keep file:

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$1.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

Your AppWrapper class fails to load because the retrofit.ErrorHandler interface is not included in main dex file.

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

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

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

if everything looks OK, but this error appears,

try to disable instant run!!!

when I disabled it all the classes were loaded properly.

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).

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.

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

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 Jack and Multidex.

Ref: Jack Issue 213484

Ref: Jack Issue 224026

The NoClassDefFound can 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 release builds, 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!

So what you really want 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 will be subject to the 64K limit.

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

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.

Here's the relevant app module 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.MultiDexApplication as noted in https://developer.android.com/studio/build/multidex.html but you want to do this only for your debug build.

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 debug and release folders next to your main module's folder. Add the following files within:

debug/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

public class BaseApplication extends Application {
}

debug/java/com/yourcompany/BaseApplication.java

public class BaseApplication extends MultiDexApplication {
}            

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.java while having differing base classes.

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:

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:

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

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

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 ErrorHandler interface, which AppWrapper implements.

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

Anyway, solution is not to implement ErrorHandler directly by AppWrapper and pull it into private variable instead.

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 :)

Add below dependency in gradle

implementation 'com.android.support:multidex:1.0.3'

In app level build.gradle,add parameters like below.

 defaultConfig {
     multiDexEnabled = true
 }

In Application class,add below line

MultiDex.install(this);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM