Есть ли способ использовать функциональные интерфейсы Java 8 на Android API ниже 24?

Я могу использовать retrolambda, чтобы включить лямбды с уровнем API Android<24. Так что это работает

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

Вместо того, чтобы использовать retrolambda, я попытался включить Java 8. Первые два примера кода все еще работают, хотя butterknife перестал работать. https://developer.android.com/preview/j8-jack.html здесь ava.util.function говорят, что поддерживается, но я все еще получаю сбой при запуске третьего, на этот раз он немного отличается

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

7 ответов

Решение

Не уверен, если вам все еще нужен ответ на этот вопрос, но другие (как я) могут.

В версии 3.0 Android Studio изначально поддерживает лямбда-функции и многие другие функции Java 8 на всех уровнях API, но некоторые (например, функциональные интерфейсы и java.util.function) по-прежнему ограничены API 24+.

Пока эта поддержка не будет расширена, android-retrostreams обеспечивает поддержку бэкпорта для большинства из них. Этот проект является "модернизированным портом" библиотеки streamsupport, которую вы также можете использовать и которая имеет множество функциональных возможностей в android-retrostreams. Библиотека streamsupport поддерживает Java 6/7, поэтому вы можете использовать его, даже если у вас нет AS 3.0+ или вы не ориентированы на Java 8, но в большинстве случаев вам лучше использовать android-retrostreams, если вы можете. Вы можете просмотреть javadocs проекта, чтобы увидеть, что именно предлагается, но основные моменты, которые я использовал, java.util.function а также java.util.Comparator,

Обратите внимание, что java в названиях пакетов заменяется java9 и некоторые имена классов и / или методов могли быть изменены незначительно. Например:

java.util.function становится java9.util.function,

в то время как

java.util.Comparator становится java9.util.Comparators (и с немного другими именами методов и шаблонами вызовов - но с той же функциональностью).

Библиотека поддержки Android (AndroidX) теперь имеет Consumer а также Supplier:

к сожалению, только эти два интерфейса добавляются на момент написания.

Теперь у нас есть 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()
    }

Плагин Android Gradle (AGP) 4.0+ добавляет поддержку пакетов java8 (например, java.util.function, добавленную в Android API 24) в более раннюю версию API:

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

Добавление строк из приведенного ниже кода в модуль APP позволяет мне использовать созданный openAPI-generator 5.1.0 модуль API-SDK java jersey с Android API <24 (я использую трикотаж для лучшей поддержки полиморфизма)

      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'
}

В качестве альтернативы, https://github.com/aNNiMON/Lightweight-Stream-API также обеспечивает поддержку backport. Как и вышеупомянутые android-retrostreams, вы должны заменить некоторые имена пакетов, используя:

com.annimon.stream.function вместо java.util.function

com.annimon.stream.ComparatorCompat вместо java.util.Comparator

Использовать

      import androidx.core.util.Consumer;

вместо

      import java.util.function.Consumer; (requires min API 24)

Пример реализации

      public static void sampleMethod(Consumer<Boolean> isClicked) {
    isClicked.accept(true);
}

использование примера реализации

      Utils.sampleMethod(new Consumer<Boolean>() {
        @Override
        public void accept(Boolean isClicked) {

        }
    });

Функциональные интерфейсы Java 8 могут быть включены для запуска на более ранних версиях Android, включив Jack Toolchain. Вы можете сделать это, добавив следующие строки кода в ваш build.gradle файл:

android{
...
  defaultConfig{
    ...
    jackOptions.enabled = true
  }
  compileOptions{
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

Однако вы должны отметить, что вам нужно отключить мгновенный запуск, так как он все еще не может работать с Java 8,

Вы также можете узнать больше информации из этого видео на канале разработчиков Android: https://www.youtube.com/watch?v=zfLKMun94Yc&index=10&list=PLWz5rJ2EKKc9tH0dRV1_HmQBXe_-qFQPl

Дайте мне знать, как это происходит.

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
dependencies {
        compile 'com.github.ipcjs:java-support:0.0.3'
}

код: https://github.com/ipcjs/java-support

Другие вопросы по тегам