以某种方式使用错误的JDK(?)构建Android应用程序



我最近更新了我的Android Studio 3项目。我想支持 Java 8 语言功能,因此在 build.gradle 中添加了以下内容:

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

然后,我在 Android 8.0.0 设备上运行我的应用。在运行时我看到

java.lang.NoSuchMethodError: No virtual method keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView; in class Ljava/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'java.util.concurrent.ConcurrentHashMap' appears in /system/framework/core-oj.jar)

我认为这与以下事实有关:Java 8 中keySet()的签名已从返回Set<K>更改为返回KeySetView<K,V>

导致异常的行如下所示:

for (Long id : mSomeMap.keySet())

KeySetView实现了Set,它肯定是Iterable,所以无论这一行被解释为 Java 7 还是 Java 8,我都会认为它会以任何一种方式工作。我对Java基础知识的理解是粗略的 - 这是怎么回事?

更新

到目前为止,我的片状理解是这样的:

虽然Android现在支持一些Java 8语言功能,但其API与Java 8并不相同。特别是 Android 的ConcurrentHashMap.keySet()实现返回一个Set,而 Java 8

的实现ConcurrentHashMap.keySet()返回一个KeySetView

。不知何故,Android Studio 设法使用标准 Java 8 JDK 编译我的应用程序,因此在运行时希望找到一种带有签名KeySetView<K,V> keySet()的方法。但是,Android的ConcurrentHashMap没有具有此签名的方法,因此我得到了NoSuchMethodError

我还没有弄清楚Android Studio如何或为什么使用不兼容的JDK进行构建。在项目结构中,选中了"使用嵌入式JDK(推荐(",因此我假设Android Studio正在使用与之捆绑的JDK进行构建。

不是解决方案

到目前为止,大多数评论/答案都指出,我可以将ConcurrentHashMap声明为解决此问题Map这是一种解决方法,而不是解决方案。如果根本问题是我的应用程序是使用错误的 JDK 构建的,那么可能存在方法签名分歧的其他情况,并且由于我无法在大型项目中实时测试 100% 的代码路径,因此我无法保证在运行时不会抛出更多NoSuchMethodErrors

我正在使用此解决方法,似乎正在工作。

private final Map<ImageView, Request> mPendingRequests =
new ConcurrentHashMap<ImageView, Request>();

只是将其转换为Map<?, ?>

for (Long id : ((Map< Long, ?>)mSomeMap).keySet())

您正在使用 ConcurrentHashMap 的特殊实现

'java.util.concurrent.ConcurrentHashMap' 的声明出现在/system/framework/core-oj.jar

没有方法keySet()

你可以声明ConcurrentMap接口:

ConcurrentMap mSomeMap = new ConcurrentHashMap();

然后像这样使用:

for (Long id : mSomeMap.keySet())

最新更新