问题
What is the proper way to import Guava into an Android project? Every time I try to use it I get a NoClassDefFoundError
.
This is what I'm doing to generate the crash. I'm using Android Studio 3.0 Canary 7.
- Create an new project
File > New > New Project
, targetAPI 26.0
, using theEmpty Activity
template. Add to
app/build.gradle
in thedependencies
sectionimplementation "com.google.guava:guava:20.0"
Add this to the onCreate method in
MainActivity.java
ImmutableList<String> foo = ImmutableList.of("A", "B", "C"); Log.d("MainActivity", foo.get(0));
Run the App and open up Logcat to see this exception:
FATAL EXCEPTION: main Process: com.letsdoit.guavaissue, PID: 14366 java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/common/collect/ImmutableList; at com.letsdoit.guavaissue.MainActivity.onCreate(MainActivity.java:20) at android.app.Activity.performCreate(Activity.java:6679) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.common.collect.ImmutableList" on path: DexPathList[[zip file "/data/app/com.letsdoit.guavaissue-1/base.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_dependencies_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_0_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_1_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_2_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_3_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_4_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_5_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_6_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_7_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_8_apk.apk", zip file "/data/app/com.letsdoit.guavaissue-1/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/com.letsdoit.guavaissue-1/lib/x86, /system/lib, /vendor/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:380) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at com.letsdoit.guavaissue.MainActivity.onCreate(MainActivity.java:20) at android.app.Activity.performCreate(Activity.java:6679) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
I'm almost certain it has to do with Gauva being large and not playing well with multidex, but am not sure what to do about it. These are some of the note worthy things I've tried to no avail:
Enabling multidex and specifying ImmutableList in the multiDexKeepFile.
Disabling instant run.
Pulled the APKs from the device and verified the Guava classes are in the APKs.
Following the recommendations in this stack overflow question.
回答1:
TL;DR
Use guava version 22.0-android
and up. Make sure to use the -android
flavor, otherwise you'll run into the NoClassDefFoundError
.
Explanation
I learned after posting the question how to manually clean the project and uninstall apks from the emulator. It turns out that version 20.0
actually does work, but I had tried version 21.0
right before then and failed to clean.
The non-android
flavors of guava as of version 21.0
are using Java 8. The android flavors and versions before 21.0
use Java 7. This is described in these release notes for version 22.0.
I tested these flavors and versions:
20.0 (Java 7)
- works21.0 (Java 8)
- doesn't work22.0 (Java 8)
- doesn't work22.0-android (Java 7)
- works
When using version 21.0
or 22.0
(no -android
) the ImmutableList
class is getting referenced but not compiled into the dex files (since it's in italics). This was causing the NoClassDefFoundError
.
APK with dangling references to ImmutableList
As the android developer docs explain
In the tree view, italicized nodes are references that do not have a definition in the selected DEX file.
It further explains that
A DEX file can reference methods and fields that are defined in a different a file. For example System.out.println() is a reference to the println() method in the Android framework.
But in this case, there is no other file that these methods and class definition should end up in. It's just failing to add them.
Contrast that to using 20.0
or 22.0-android
, where the ImmutableList class actually gets compiled in.
APK with ImmutableList defined
And the app starts up as expected.
来源:https://stackoverflow.com/questions/48333035/how-to-import-guava-into-android-applications