【问题标题】:Is there a way to use Java 8 functional interfaces on Android API below 24?有没有办法在 24 以下的 Android API 上使用 Java 8 功能接口?
【发布时间】:2016-07-27 08:00:30
【问题描述】:

我可以使用 retrolambda 来启用 Android API 级别

myButton.setOnClickListener(view -> Timber.d("Lambdas work!"));

这也有效

Runnable runLater = () -> Timber.d("Lambdas work!");
runLater.run();

但是这个没有

Consumer<Integer> runLaterWithInt = (Integer i) -> Timber.d("i = " + i);
runLaterWithInt.accept(3);

最后一个适用于 Android API Level 24,但在其他设备上此代码会导致崩溃

java.lang.NoClassDefFoundError: com.retrolambdatry.MainActivity$$Lambda$1

我尝试启用 Java 8,而不是使用 retrolambda。前两个代码示例仍然有效,尽管黄油刀停止工作。 https://developer.android.com/preview/j8-jack.html#configuration这里ava.util.function据说支持,但是我运行第三个的时候还是会崩溃,这次有点不一样

java.lang.NoClassDefFoundError: com.retrolambdatry.MainActivity$-void_onCreate_android_os_Bundle_savedInstanceState_LambdaImpl1

【问题讨论】:

  • 这个问题的标题不好; lambdas 实际上被向后移植到旧的 Android 版本,所以你不需要 Retrolambda。只需安装新的 Android Studio 和构建工具。
  • 也许它的标题不好。据我了解,如果我有 Android N SDK 并且启用 Jack 编译选项,则不需要 retorlambda。无论哪种方式,Lambda 都可以工作。但是来自“java.util.function”的功能接口仍然没有。
  • 问题是 Jack 编译器阻止了数据绑定库的使用(参见here)。这就是为什么很多人目前可能不愿意使用 Jack,而是使用 Retrolambda 作为获取 lambda 表达式的替代方案(直到这些问题在未来的 Android Studio 版本中得到修复)。

标签: java android lambda functional-interface retrolambda


【解决方案1】:

不确定您是否还需要这个问题的答案,但其他人(比如我自己)可能会。

作为 3.0 版,Android Studio natively supports lambda functions 和所有 API 级别上的许多其他 Java 8 函数,但一些(如功能接口和 java.util.function)仍然仅限于 API 24+。

在扩展支持之前,android-retrostreams 为其中的大部分提供反向端口支持。该项目是streamsupport library 的“升级端口”,您也可以使用它,并且具有 android-retrostreams 中的许多功能。 streamsupport 库支持低至 Java 6/7,因此即使您没有 AS 3.0+ 或不针对 Java 8,您也可以使用它,但在大多数情况下,您最好使用 android-retrostreams,如果你可以。您可以浏览该项目的 javadocs 以查看所提供的确切内容,但我使用的重点是 java.util.functionjava.util.Comparator

请注意,包名中的java 已替换为java9,并且某些类和/或方法名可能已略有更改。例如:

java.util.function 变为 java9.util.function

同时

java.util.Comparator 变为 java9.util.Comparators(方法名称和调用模式略有不同 - 但功能相同)。

【讨论】:

  • 更正:android-retrostreams 适用于 Java 7,如果您考虑使用 Java 7 Oracle / OpenJDK VM。它确实适用于 API 级别 15 或 14 的 Android 设备,无论当时的 Java 版本是什么,提供您使用 Android Studio 3.x 及其 Java 8 功能为此类设备开发应用程序(不适用于 Android Studio 2.3.x)。如果您需要一个在真正的 Java 6 / 7 VM(Sun 等)上确实工作的 Stream API 反向移植,您必须使用streamsupport
  • 啊,我的错。 android-retrostreams 自述文件听起来好像他们只放弃了对 Java 6 的支持,并且即使您没有明确针对 Java 8,它也适用于 Android Studio。不过,我从未真正尝试过。以防万一,我将进行编辑以进行澄清。
  • 您在 Android Studio 3.x 中定位的 Java 版本有什么关系?最后,是 minSDKVersion 决定了您的应用程序是否可以在 Marshmallow 上运行。因此,为了避免可能的混淆:让 minSDKVersion = 23 (Marshmallow),然后在 Android Studio 3.x 中“定位”Java 8 并使用android-retrostreams,你会没事的。我的意思是,android-retrostreams jar 文件无法在 Java 7 标准版 VM(来自 Oracle、IBM 的 JRE ...)上运行
  • 我想说的是,如果您想使用 Java 8 语言功能(如 lambda、方法引用或接口默认方法),则无论如何都必须以 Java 8 为目标。只要您使用特定于 Java 8 的 API 调用(如 java.util.function 中的某些内容),这与 minSDKVersion 完全断开。@987654339 @ 为这些 Java 8 API 带来了替换,这些 API 甚至可以在 Ice Cream Sandwich(肯定是 Java 6)上工作。
  • retro-lambda 有什么不同? @VerumCH 已编辑:仔细阅读后,retrolambda 为 lacks support for 3rd-party libs。我们真的应该使用android-retrostreams
【解决方案2】:

Android 支持库(AndroidX)现在有ConsumerSupplier

在写作时可悲的是only these two interfaces gets added

现在我们有了 Kotlin,它不需要你明确指定功能接口:

    fun test() {
        val text = withPrintStream {
            it.println("Header bla bla ")
            it.printf("%s, %s, %s,", "a", "b", "c").println()
        }
    }

    // Equivalent to the following code in Java:
    //     Consumer<PrintStream> action;
    //     action.accept(ps);
    fun withPrintStream(action: (PrintStream) -> Unit): String {
        val byteArrayOutputStream = ByteArrayOutputStream()
        val ps = PrintStream(byteArrayOutputStream)
        action(ps)
        ps.flush()
        return byteArrayOutputStream.toString()
    }

【讨论】:

  • 这是一个老问题。 Kotlin 解决了这个问题,但在询问 Kotlin 时并不是一个真正的选择。
  • 这个答案对我有帮助,因为我现在被 Java 困住了。干杯!
  • 这仍然很有帮助,因为它在使用 Java 代码时也适用于 API 级别
  • 真的很有帮助!!!除了这个库-desugaring 需要添加developer.android.com/studio/write/…
【解决方案3】:

作为替代方案,Lightweight-Stream-API 还提供反向端口支持。就像上面提到的 android-retrostreams 一样,您必须使用以下方法替换一些包名称:

com.annimon.stream.function 而不是 java.util.function

com.annimon.stream.ComparatorCompat 而不是 java.util.Comparator

【讨论】:

    【解决方案4】:

    Android Gradle 插件 (AGP) 4.0+ 在低 API 版本上添加了对 java8 包(例如 java.util.function,添加到 Android API 24)的向后移植支持:

    https://developer.android.com/studio/write/java8-support#library-desugaring

    将以下代码中的行添加到 APP 模块允许我使用 openAPI-generator 5.1.0 生成的 java jersey API-SDK 模块和 Android API

    android {
      defaultConfig {
        // Required when setting minSdkVersion to 20 or lower
        multiDexEnabled true
      }
    
      compileOptions {
        // Flag to enable support for the new language APIs
        coreLibraryDesugaringEnabled true
        // Sets Java compatibility to Java 8
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
      }
    }
    
    dependencies {
      coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
    }
    

    【讨论】:

      【解决方案5】:
      allprojects {
          repositories {
              maven { url 'https://jitpack.io' }
          }
      }
      dependencies {
              compile 'com.github.ipcjs:java-support:0.0.3'
      }
      

      代码:ipcjs/java-support

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-24
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多