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
In Android, the compiler converts our source code into DEX(Dalvik Executable) file. So, in this blog, we will learn about Dex and Multidex in Android. Especially, this blog is for those Android developers who get 64K method limit exceeded error while building APK. This error comes due to DEX.
Show activity on this post. You can disable multidex only if your project doesn't exceed either 65k methods limitation or 65k fields limitation. People seems to be unaware about the 65k fields limitation. You can hit the fields limitation if you're using huge total of resources like drawable, string id, etc.
Getting past this limit requires that you configure your app build process to generate more than one DEX file, known as a multidex configuration. So, the feature is: it allows your complex app to compile. The scenarios for using it are when your app fails to compile due to hitting the 64K DEX method reference limit.
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 you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With