如何将 Guava 导入 Android 应用程序 [英] How to import Guava into Android applications

查看:19
本文介绍了如何将 Guava 导入 Android 应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将 Guava 导入 Android 项目的正确方法是什么?每次我尝试使用它时,我都会收到 NoClassDefFoundError.

What is the proper way to import Guava into an Android project? Every time I try to use it I get a NoClassDefFoundError.

这就是我正在做的事情来产生崩溃.我使用的是 Android Studio 3.0 Canary 7.

This is what I'm doing to generate the crash. I'm using Android Studio 3.0 Canary 7.

  1. 使用Empty Activity 模板创建一个新项目File > New > New Project,目标API 26.0.
  2. 添加到 dependencies 部分的 app/build.gradle

  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"

  • 将此添加到MainActivity.java

    ImmutableList<String> foo = ImmutableList.of("A", "B", "C");
    Log.d("MainActivity", foo.get(0));
    

  • 运行 App 并打开 Logcat 看到这个异常:

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

  • 我几乎可以肯定这与 Gauva 很大并且不能很好地使用 multidex 有关,但我不确定该怎么做.这些是我尝试过但无济于事的一些值得注意的事情:

    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. multiDexKeepFile 中启用 multidex 并指定 ImmutableList.

    1. Enabling multidex and specifying ImmutableList in the multiDexKeepFile.

    禁用即时运行.

    从设备中提取 APK 并验证 Guava 类在 APK 中.

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

    遵循此堆栈溢出中的建议 问题.

    Following the recommendations in this stack overflow question.

    推荐答案

    TL;DR

    使用 guava 版本 22.0-android 及更高版本.确保使用 -android 风格,否则你会遇到 NoClassDefFoundError.

    Use guava version 22.0-android and up. Make sure to use the -android flavor, otherwise you'll run into the NoClassDefFoundError.

    说明

    我在发布问题后了解到如何手动清理项目并从模拟器卸载 apk.事实证明 20.0 版本确实有效,但我在此之前尝试过 21.0 版本并且未能清理.

    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.

    21.0 版本的非-android guava 版本使用Java 8.21.0 之前的android 版本和版本使用Java 7. 22.0 版的发行说明对此进行了描述.

    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) - 有效
    • 21.0 (Java 8) - 不工作
    • 22.0 (Java 8) - 不工作
    • 22.0-android (Java 7) - 有效
    • 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

    当使用版本 21.022.0(没有 -android)时,ImmutableList 类被引用但没有编译到 dex 文件中(因为它是斜体的).这导致了 NoClassDefFoundError.

    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.

    带有对 ImmutableList 的悬空引用的 APK

    正如 android 开发者文档解释

    As the android developer docs explain

    在树视图中,斜体节点是没有所选 DEX 文件中的定义.

    In the tree view, italicized nodes are references that do not have a definition in the selected DEX file.

    进一步说明

    DEX 文件可以引用定义在不同的文件.例如 System.out.println() 是对Android 框架中的 println() 方法.

    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.

    与使用 20.022.0-android 相比,ImmutableList 类实际上是在其中编译的.

    Contrast that to using 20.0 or 22.0-android, where the ImmutableList class actually gets compiled in.

    定义了 ImmutableList 的 APK

    应用按预期启动.

    这篇关于如何将 Guava 导入 Android 应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆