如何将 Guava 导入 Android 个应用程序
How to import Guava into Android applications
将 Guava 导入 Android 项目的正确方法是什么?每次我尝试使用它时,我都会得到 NoClassDefFoundError
.
这就是我造成崩溃的原因。我正在使用 Android Studio 3.0 Canary 7.
- 创建一个新项目
File > New > New Project
,目标 API 26.0
,使用 Empty Activity
模板。
添加到 dependencies
部分的 app/build.gradle
implementation "com.google.guava:guava:20.0"
将此添加到MainActivity.java
中的onCreate方法
ImmutableList<String> foo = ImmutableList.of("A", "B", "C");
Log.d("MainActivity", foo.get(0));
运行 应用程序并打开 Logcat 以查看此异常:
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 配合使用有关,但我不确定该怎么做。这些是我尝试过但无济于事的一些值得注意的事情:
启用 multidex 并在 multiDexKeepFile.
中指定 ImmutableList
禁用即时 运行.
从设备中提取 APK 并验证 Guava 类 在 APK 中。
遵循此堆栈溢出中的建议 question。
TL;DR
使用 guava 版本 22.0-android
及更高版本。确保使用 -android
风格,否则你会 运行 进入 NoClassDefFoundError
.
说明
我在发布问题后了解到如何手动清理项目并从模拟器中卸载 apk。事实证明 20.0
版本确实有效,但我之前尝试过 21.0
版本但无法清理。
从 21.0
版本开始,非-android
版本的番石榴正在使用 Java 8. 21.0
之前的 android 版本和版本使用 Java 7. 这些 release notes 版本 22.0.
中对此进行了描述
我测试了这些口味和版本:
20.0 (Java 7)
- 有效
21.0 (Java 8)
- 无效
22.0 (Java 8)
- 无效
22.0-android (Java 7)
- 有效
当使用版本 21.0
或 22.0
(没有 -android
)时,ImmutableList
class 被引用但未编译到 dex 文件中(因为它是斜体)。这导致 NoClassDefFoundError
.
APK with dangling references to ImmutableList
作为 android developer docs 解释
In the tree view, italicized nodes are references that do not have a
definition in the selected DEX file.
进一步说明
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.
但在这种情况下,这些方法和 class 定义应该最终不存在于其他文件中。只是无法添加它们。
与使用 20.0
或 22.0-android
相比,ImmutableList class 实际上是在其中编译的。
APK with ImmutableList defined
应用程序按预期启动。
将 Guava 导入 Android 项目的正确方法是什么?每次我尝试使用它时,我都会得到 NoClassDefFoundError
.
这就是我造成崩溃的原因。我正在使用 Android Studio 3.0 Canary 7.
- 创建一个新项目
File > New > New Project
,目标API 26.0
,使用Empty Activity
模板。 添加到
dependencies
部分的app/build.gradle
implementation "com.google.guava:guava:20.0"
将此添加到
中的onCreate方法MainActivity.java
ImmutableList<String> foo = ImmutableList.of("A", "B", "C"); Log.d("MainActivity", foo.get(0));
运行 应用程序并打开 Logcat 以查看此异常:
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 配合使用有关,但我不确定该怎么做。这些是我尝试过但无济于事的一些值得注意的事情:
启用 multidex 并在 multiDexKeepFile.
中指定 ImmutableList
禁用即时 运行.
从设备中提取 APK 并验证 Guava 类 在 APK 中。
遵循此堆栈溢出中的建议 question。
TL;DR
使用 guava 版本 22.0-android
及更高版本。确保使用 -android
风格,否则你会 运行 进入 NoClassDefFoundError
.
说明
我在发布问题后了解到如何手动清理项目并从模拟器中卸载 apk。事实证明 20.0
版本确实有效,但我之前尝试过 21.0
版本但无法清理。
从 21.0
版本开始,非-android
版本的番石榴正在使用 Java 8. 21.0
之前的 android 版本和版本使用 Java 7. 这些 release notes 版本 22.0.
我测试了这些口味和版本:
20.0 (Java 7)
- 有效21.0 (Java 8)
- 无效22.0 (Java 8)
- 无效22.0-android (Java 7)
- 有效
当使用版本 21.0
或 22.0
(没有 -android
)时,ImmutableList
class 被引用但未编译到 dex 文件中(因为它是斜体)。这导致 NoClassDefFoundError
.
APK with dangling references to ImmutableList
作为 android developer docs 解释
In the tree view, italicized nodes are references that do not have a definition in the selected DEX file.
进一步说明
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.
但在这种情况下,这些方法和 class 定义应该最终不存在于其他文件中。只是无法添加它们。
与使用 20.0
或 22.0-android
相比,ImmutableList class 实际上是在其中编译的。
APK with ImmutableList defined
应用程序按预期启动。