Есть ли способ использовать функциональные интерфейсы 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
:
- androidx.core.util.Consumer (появляется в
androidx.appcompat:appcompat:1.0.2
) - androidx.core.util.Supplier (появляется в
androidx.appcompat:appcompat:1.1.0-alpha01
)
к сожалению, только эти два интерфейса добавляются на момент написания.
Теперь у нас есть 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'
}