使用Java 8的android上的kotlin集合

在Android开发中,虽然Kotlin已成为首选语言,但使用Java 8特性时需注意兼容性。文章指出,部分Java 8功能如Stream在Android 24以下版本不受支持,可能导致NoSuchMethod异常。Kotlin的某些集合方法在低版本Android上依赖Java 8,这在编译时可能不会暴露问题,但在实际运行时会导致错误。解决方案包括使用Elvis运算符或Kotlin内建方法。为避免此类问题,开发者应关注Kotlin集合类的平台依赖性,并在最低支持的Android版本上测试代码。
摘要由CSDN通过智能技术生成

We all love Kotlin, Google has chosen it as the first-class language for Android development and the ASOS Android team consider it the only language for new feature implementation.

我们都很喜欢Kotlin,Google已选择它作为Android开发的一流语言,而ASOS Android团队则认为它是唯一实现新功能的语言。

Since Kotlin is so good, it begs the question of whether we need to consider Java any more? Google has a specific page regarding the Java 8 support on Android Studio and Jake Wharton has written a useful blog piece regarding Java 8 support on Android. With the D8 desugars, Java 8 features lambda, default method and method references which are fully supported for all Android API versions. But some Java 8 features like Stream, Time etc are only supported for Android version 24+. Why do you need to consider the different support for Java 7 and Java 8 on Android if you’re using Kotlin?

由于Kotlin如此出色,这就引出了一个问题,我们是否需要再考虑Java? Google在有关Android Studio上对Java 8的支持上有专门的页面,杰克·沃顿(Jake Wharton)撰写了一篇有关AndroidJava 8的支持的有用的博客文章。 借助D8 desugars,Java 8具有lambda,默认方法和方法引用,所有Android API版本都完全支持该功能。 但是某些Java 8功能(例如Stream,Time等)仅在Android 24+版本中受支持。 如果您使用的是Kotlin,为什么需要考虑对Android 7和Java 8的不同支持?

Recently we had an issue when running Kotlin collection methods on devices running below Android 24. Here’s a code snippet.

最近,在运行Android 24以下版本的设备上运行Kotlin收集方法时,我们遇到了一个问题。这是一个代码段。

Image for post

As you can see, the code is very simple; it will return the default resource if the user hasn’t previously set any payment methods. When we ran the code, it passed our UI tests (Our test devices are all 24+) and Unit tests (Java 8). But when we ran the app on a device below 24, it throws a NoSuchMethod exception.

如您所见,代码非常简单; 如果用户以前未设置任何付款方式,它将返回默认资源。 当我们运行代码时,它通过了我们的UI测试(我们的测试设备均为24+)和单元测试(Java 8)。 但是,当我们在低于24的设备上运行该应用程序时,它将引发NoSuchMethod异常。

java.lang.NoSuchMethodError: No virtual method getOrDefault(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; in class Ljava/util/EnumMap; or its super classes (declaration of 'java.util.EnumMap' appears in /system/framework/core-libart.jar)

Thankfully the pre-launch test on the Play store identified this issue and sent us an alert.

值得庆幸的是,在Play商店进行的发布前测试发现了此问题,并向我们发送了警报。

Why did this error arise given we were using Kotlin? If you check the API document or the source code in Kotlin Github, you’ll find the annotation PlatformDependent and target JDK 1.8 for getOrDefaultmethod. When you decompile the Kotlin code, you can see the method java.util.EnumMap.getOrDefault is used.

考虑到我们正在使用Kotlin,为什么会出现此错误? 如果您在Kotlin Github中检查API文档或源代码,则将找到批注PlatformDependent并将目标JDK 1.8用作getOrDefault方法。 反编译Kotlin代码时,可以看到使用了java.util.EnumMap.getOrDefault方法。

The fix is really simple, you can either use Elvis operator ?:

修复非常简单,您可以使用Elvis运算符 ?:

resources[paymentType] ?: default

Or, if you want to use a Kotlin method:

或者,如果您想使用Kotlin方法:

resources.getOrElse(paymentType, {default})

The methodgetOrElse is the same as using Elvis operator. The auto Kotlin converter in Android studio also converts the getOrDefaultmethod using Elvis operator.

getOrElse方法与使用Elvis运算符相同。 Android studio中的自动Kotlin转换器还使用Elvis运算符转换getOrDefault方法。

@kotlin.internal.InlineOnly
public inline fun <K, V> Map<K, V>.getOrElse(key: K, defaultValue: () -> V): V = get(key) ?: defaultValue()

Fixing the issue is simple, but why is the code platform dependent in the first place? From the document, we can see the platform dependent annotation specifies:

解决该问题很简单,但是为什么代码平台首先要依赖于此? 从文档中 ,我们可以看到依赖于平台的注释指定:

the corresponding built-in method exists depending on platform. Current implementation for JVM looks whether method with same JVM descriptor exists in the module JDK.

取决于平台存在相应的内置方法。 JVM的当前实现查看模块JDK中是否存在具有相同JVM描述符的方法。

If you check the Collection class in Kotlin, two methods are annotated as PlatformDependent: getOrDefault(key, default) and remove(key, value). They are both introduced from Java 8 . Android’s support for this bytecode requires a minimum API of 24 but it will give a lint check warning if your minimum version is below 24. Here’s a very simple snip to call these methods directly in the Java class and the lint check which will show the warning directly in the Android Studio.

如果您在Kotlin中检查Collection类 ,则将两种方法标注为PlatformDependentgetOrDefault(key, default)remove(key, value) 。 它们都是从Java 8引入的。 Android对此字节码的支持要求最低API为24,但是如果最低版本低于24,它将给出lint检查警告。这是一个非常简单的片段,可以直接在Java类中调用这些方法,而lint check将显示警告直接在Android Studio中。

Image for post

When you call it from Kotlin, it will show the same warning if it’s a HashMap class, but it doesn’t show the same warning when you call from an EnumMap or TreeMap. That’s why our CI system doesn’t report this issue.

从Kotlin调用它时,如果它是HashMap类,它将显示相同的警告,但是从EnumMapTreeMap调用时,它不会显示相同的警告。 这就是我们的CI系统不报告此问题的原因。

Image for post

What can we do to prevent this issue from happening in the future? Pay more attention to the Kotlin collection classes when using them on Android and always test your code on devices running the minimum Android version you supported. In our CI process, we are trying to add minimum support devices to catch the issue in the pull request review state and have nightly build releases in the internal test channel to make full use of the pre-launch test.

我们怎样做才能防止将来发生此问题? 在Android上使用Kotlin集合类时,请多加注意,并始终在运行您支持的最低Android版本的设备上测试代码。 在我们的CI流程中,我们正在尝试添加最少的支持设备以在请求请求审核状态中捕获问题,并在内部测试渠道中每晚发布版本以充分利用预发布测试。

My name is Peng Jiang, I’m a Lead Android Engineer at ASOS and am passionate about simple and well-crafted code. In my spare time, I also play with Swift and Flutter. At ASOS, we’re always looking for strong, friendly and talented developers. You’ll only need to write Kotlin here. If that sounds interesting to you, do get in touch!

我叫Peng Jiang,我是ASOS的一名Android首席工程师,对简单而精心编写的代码充满热情。 在业余时间,我还玩Swift和Flutter。 在ASOS,我们一直在寻找强大,友好和有才华的开发人员。 您只需要在这里写Kotlin。 如果您觉得这很有趣,请与我们联系!

翻译自: https://medium.com/asos-techblog/kotlin-collection-on-android-with-java-8-ac3f8609440

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值