How to import Guava into Android applications

北战南征 提交于 2021-02-05 10:47:05

问题


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.

  1. Create an new project File > New > New Project, target API 26.0, using the Empty Activity template.
  2. Add to app/build.gradle in the dependencies section

    implementation "com.google.guava:guava:20.0"
    
  3. Add this to the onCreate method in MainActivity.java

    ImmutableList<String> foo = ImmutableList.of("A", "B", "C");
    Log.d("MainActivity", foo.get(0));
    
  4. 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:

  1. Enabling multidex and specifying ImmutableList in the multiDexKeepFile.

  2. Disabling instant run.

  3. Pulled the APKs from the device and verified the Guava classes are in the APKs.

  4. 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) - works
  • 21.0 (Java 8) - doesn't work
  • 22.0 (Java 8) - doesn't work
  • 22.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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!