11

So I've just hit the maximum method count limit for my android project, which fails to build with the following error message:

Error: null, Cannot fit requested classes in a single dex file (# methods: 117407 > 65536)

I understand what the message means, and how to resolve it (running proguard, enabling multidex etc). My problem is that I don't understand why I'm suddenly getting this message - I was doing was removing some old bits of code which were redundant, hit build, and now I get this message.

Question 1: How can it be possible that my method count (117407 according to the error message) is suddenly massively over the limit (65536), even though I did not add any library dependencies? I actually removed code, and suddenly I have like 50 thousand methods too many?

Now this is where it gets really weird: I wanted to analyse the APK to figure out what's causing the problem, but of course I can't build it. So instead of enabling multidex I decided to revert my code to yesterday (which definitely absolutely did build fine yesterday - I have the app on my phone to prove it!), but I still get this build error message. I don't understand how this is possible. I tried reverting to several days ago, same thing (cloning a new repo and checking out an earlier commit).

So, question 2: How am I getting this build error for the exact same code which just yesterday built fine without error?

The only thing I can think of is that a library that I am using as a dependency has suddenly increased in size - but I'm declaring specific versions of everything in my gradle build, for example:

// RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'

// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'

So, surely my dependencies should not have changed?

Any ideas what I can do to figure this out are greatly appreciated. I've tried cleaning my project, and invalidating caches/restart in android studio. I really don't want to enable multidex or have to run proguard on my debug build.

Here's the full build.gradle:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 28
    defaultConfig {
    applicationId "XXXXXXXXX"
    minSdkVersion 19
    targetSdkVersion 28
    versionCode 1
    versionName "0.1"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    vectorDrawables.useSupportLibrary = true  // see https://developer.android.com/studio/write/vector-asset-studio#sloption
}
buildTypes {
    release {
        minifyEnabled false
        // Do code shrinking!
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

// Core stuff
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-vector-drawable:28.0.0'
implementation 'com.google.android.gms:play-services-wearable:16.0.1'

// Dagger
implementation 'com.google.dagger:dagger:2.21'
kapt 'com.google.dagger:dagger-compiler:2.21'
// Dagger for Android
implementation 'com.google.dagger:dagger-android:2.21'
implementation 'com.google.dagger:dagger-android-support:2.21' // if you use the support libraries
kapt 'com.google.dagger:dagger-android-processor:2.21'

// Constraint layout
implementation 'com.android.support.constraint:constraint-layout:1.1.3'

// Associated WearOS project
wearApp project(':wear')

// Common library project
implementation project(':common')

// These were added to resolve gradle error on the 'com.android.support:appcompat-v7:28.0.0' implementation:
// All com.android.support libraries must use the exact same version specification (mixing versions can lead to
// runtime crashes). Found versions 28.0.0, 26.1.0. Examples include com.android.support:animated-vector-drawable:28.0.0
// and com.android.support:support-media-compat:26.1.0
// This seems to be related to linking the wear project. If the wear project was not linked, the error went away.
implementation 'com.android.support:support-media-compat:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'

// RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'

// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
// Retrofit RxJava
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
// Retrofit logging:
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1'

// Room
def room_version = "1.1.1"
implementation "android.arch.persistence.room:runtime:$room_version"
implementation "android.arch.persistence.room:common:$room_version"
implementation "android.arch.persistence.room:rxjava2:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"

// For modern time handling (java.time requires API 26 or higher)
implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1'

// Graphing
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha'

// Dropbox
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.11'

// OpenCSV
implementation 'com.opencsv:opencsv:4.5'

}

EDIT

So after enabling multidex, there are some heavy dependencies showing up under the following TLDs when I analyse the APK using Android Studio (I'm not sure if I should be looking at defined or referenced method numbers?):

  • com.dropbox: 26000 defined methods, 34000 referenced methods
  • com.android (mainly support libraries): 18700 defined, 24600 referenced
  • org.apache (commons, log etc): 15000 defined, 15700 referenced

These alone take me up to the limit. I still don't get why this is suddenly happening though :( Surely if I have not added any libraries, these numbers should not have changed?

James Allen
  • 6,406
  • 8
  • 50
  • 83
  • Can you post your entire build.gradle file (minus the identifications if you'd like)? – Andres S Feb 27 '19 at 18:10
  • I've added the build.gradle for the project in question. It references a common library project called "common", and a linked WearOS project – James Allen Feb 27 '19 at 18:31
  • @JamesAllen This error comes from d8/r8, which became the default compiler in Android Studio 3.1. It is possible that this new compiler behaves differently from dx/proguard toolchain (perhaps you've built your previous version with dx/proguard). You can try to revert to dx using `android.enableD8=false` and see if you're getting the same error. – Alex Lipov Mar 01 '19 at 12:41
  • 1
    I had this problem today as well. Even reverting to previous commits didn't help. What I also discovered is that if you just run the app either in debug or release mode, it works. But running Build from the build menu causes this problem. WTF?? My app is very small and doesn't have a ton of dependencies. – Johann May 25 '19 at 08:37

12 Answers12

21

Simple add this to your gradle (Module: app) >> multiDexEnabled true

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

then Rebuild Project in Menu click => Build>Rebuild Project.

Driss Baidou
  • 305
  • 3
  • 7
  • Thank you for the suggestion, but I have already enabled multidex. This isn't my question. As I say at the start, "I understand what the message means, and how to resolve it (running proguard, enabling multidex etc). My problem is that I don't understand why I'm suddenly getting this message" – James Allen Jul 04 '19 at 16:32
  • 1
    That solution helped me to solve the problem when adding `implementation 'com.google.zxing:core:3.4.0'`. Thank you, @Driss Baidou – Mark Delphi Nov 26 '19 at 10:17
5

After looking at your entire build gradle file, your issue definitely stems from your dependencies! Attempt to clean them up and remove as many as you can that you don't use. Chances are you were very close to the limit and any of those dependencies may have been cached using older versions. You can attempt to remove the entire build folder (and clean your gradle cache) but I am fairly certain the issue will not go away.

If all of these dependencies are required unfortunately you will have to go the routes you mentioned, either multi-dex or minifying debug builds. Multi-dex should be ok and shouldn't cause any unforeseen issues while minifying will slow down your builds and potentially cause Android Studio to become unstable (especially instant run/apply changes!)

Good luck, one thing to take from this is to keep your dependencies clean and precise, only add when absolutely needed, and if all else fails, multi-dex is your friend.

Andres S
  • 471
  • 1
  • 5
  • 19
  • Thanks for your help! I'm just trying to get my head around why the method count suddenly exploded to nearly double the limit. I'm very intrigued by your line "any of those dependencies may have been cached using older versions" - this sounds like a possible answer, can you explain further? – James Allen Feb 27 '19 at 18:44
  • Gradle/AS caches quite a bit. It's possible that the caching went wrong (or weirdly right) and was under reporting the methods (possibly even truncating some dependencies) that did not affect your code. When the cache went stale, or you forced a rebuild, gradle "fixed" itself and brought up issues. You could potentially try clearing everything (all build folders, all gradle remnants, from all linked projects) and see if it changes anything, but I'm not so sure about it. – Andres S Feb 27 '19 at 18:50
  • Okay thanks - that must be it. I can't see any other cause. – James Allen Feb 27 '19 at 18:55
  • Also note that Android support dependencies and possibly even the kotlin plugins may have updated and caused changes that didn't remove duplicate method references (that are never removed) so while a bug is probably low priority since it doesn't cause any (big) problems. The gradle ecosystem is a mess of optimization and unfortunately something that would take years of deep research to even begin to understand. I run into these kinds of issues daily and the one thing that has helped me is to clean and organize dependencies when it gets out of hand and prevent random dep additions. – Andres S Feb 27 '19 at 18:58
3

None of the answers they gave you were exhaustive. The problem lies in the Multidex. You must add the library in the app gradle:

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

After, you should add in the defaultConfig of the app gradle:

multiDexEnabled true
octobus
  • 1,246
  • 1
  • 14
  • 20
Hamza Rasheed
  • 179
  • 1
  • 2
  • 1
    This helped, thanks. If into androidx, use implementation 'androidx.multidex:multidex:2.0.1' instead of the above. – Masiorama Apr 29 '20 at 10:47
1

From the Android docs:

"If your minSdkVersion is set to 21 or higher, multidex is enabled by default and you do not need the multidex support library."

As an alternative to manually enabling multidex, you could simply increase your minSdkVersion if possible.

0

I would recommend building the application with multidex, and then extracting the method ids from the multiple dex files from the new apk, and also extract the method ids from the old, single-dex apk and comparing the two lists.

roughly, something like:

baksmali list dex new.apk
baksmali list method new.apk/classes.dex > new.list
baksmali list method new.apk/classes2.dex >> new.list
sort new.list > new.sorted.list

baksmali list method old.apk > old.list
diff new.sorted.list old.list

Although, if you're using proguard, you may need to figure out some way to apply the reverse proguard name mangling before comparing the lists.

JesusFreke
  • 19,784
  • 5
  • 65
  • 68
  • Thanks, although unfortunately I don't have an old APK to compare it to, and I can't seem to build earlier versions of my code either which is the strange part. I ended up enabling multidex, and I then analysed the APK using android studio - see updated question :) – James Allen Feb 27 '19 at 19:11
0

After reading your question I can only suggest try invalidate cache and restart after and force refresh your dependency using this .

./gradlew build --refresh-dependencies
End User
  • 792
  • 6
  • 14
0

As your problem, I had to delete the build folder and the *.iml files (Android Studio project files) y I had to recreate the project, then the build and then all worked fine again.

Jairo Martínez
  • 465
  • 5
  • 9
0

I encountered the same issue and the solution was to enable Instant Run under File -> Setting -> Build, Execution, Deployment -> Instant Run and that solved my problem. Hope it's helpful.

ali sampson
  • 321
  • 4
  • 7
0

I tried this. hopes it helps, found it on some documentation ( forgot the url :( )

build.gradle app

dependencies {...
grdef multidex_version ='2.0.1'

implementation "androidx.multidex:multidex:$multidex_version"
}...
Rudy Rosa
  • 5
  • 5
0

in bulid.gradle app

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

android {
    multiDexEnabled true

}

0

android > app > build.gradle

  1. android {
    
        defaultConfig {
            versionCode 1
            versionName "1.0"
          +  multiDexEnabled true
        }
    }
    
  2. Add implementation 'com.android.support:multidex:1.0.3' in dependencies block

    dependencies {
     + implementation 'com.android.support:multidex:1.0.3'
    }
    
4b0
  • 21,981
  • 30
  • 95
  • 142
0

Community wiki Its easy just increase this minSdkVersion, targetSdkVersion :

Old:

defaultConfig { minSdkVersion 19 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName }

New:

defaultConfig { minSdkVersion 21 targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName }

also this compileSdkVersion:

Old:

android { compileSdkVersion 28

New:

android { compileSdkVersion 29

Jesus Loves You
  • 261
  • 5
  • 17