Coin-Insider.ru Новости криптовалют, инвестиций, майнинга и бизнеса

Android: инструменты программиста и новые возможности Kotlin

Структурированный параллелизм в Kotlin

Structured concurrency — статья Романа Елизарова из JetBrains о новой возможности библиотеки kotlinx.coroutines 0.26.0, а точнее даже не возможности, а об изменении в подходе к написанию распараллеленного кода на Kotlin.

Суть новой функции проста. Представим, что у нас есть такой код:

fun requestSomeData() {
    launch(UI) {
        updateUI(performRequest())
    }
}

Функция создает новую корутину в основном потоке приложения (контекст UI), а затем запускает блокируемую (suspend) функцию performRequest, которая делает какую-то фоновую работу, не блокируя основной поток.

Все хорошо, но у нас нет возможности контролировать жизненный цикл корутин. Что, если работа функции performRequest будет слишком долгой и пользователь, не дождавшись ответа, вернется на предыдущий экран приложения или запустит другой элемент интерфейса? Нам не нужны висящие в фоне корутины.

Как раз для этого и пригодится новая функция. Теперь корутины можно (и нужно) ограничить своего рода «областью действия». Например, если объявить активность, из которой вызывается функция requestSomeData, таким образом:

class MyActivity : AppCompatActivity(), CoroutineScope {
    ...
}

И слегка изменить саму функцию, исключив из нее контекст (UI):

fun requestSomeData() {
    launch {
        updateUI(performRequest())
    }
}

Тогда запуск всех корутин будет происходить в одной области действия, ограниченной активностью. Как только пользователь закроет активность, все корутины будут завершены.

Эту же возможность можно использовать для объединения зависящих друг от друга операций. Например, следующий код позволяет выполнить фоновую загрузку двух изображений одновременно, а затем объединить их:

suspend fun loadAndCombine(name1: String, name2: String): Image { 
    val deferred1 = async { loadImage(name1) }
    val deferred2 = async { loadImage(name2) }
    return combineImages(deferred1.await(), deferred2.await())
}

Хорошо и удобно, но есть проблемы. Что, если будет завершена корутина, вызывавшая эту функцию? Мы получим две корутины-беспризорника. А что, если загрузка одного изображения закончится неудачей? Второе изображение продолжит загружаться, хотя нам это уже не нужно.

Выход:

suspend fun loadAndCombine(name1: String, name2: String): Image =
    coroutineScope { 
        val deferred1 = async { loadImage(name1) }
        val deferred2 = async { loadImage(name2) }
        combineImages(deferred1.await(), deferred2.await())
    }

Бенчмарк последовательностей Kotlin

Benchmarking Kotlin Sequences — после обновления до Kotlin 1.2.70 каждый программист должен был заметить, что среда разработки теперь предлагает конвертировать коллекции (те же списки, например) в последовательности (sequence) перед их дальнейшей обработкой (Call chain on collection should be converted into Sequence). Но зачем это нужно и не приведет ли дополнительная конвертация к оверхеду?

Официальный текст анонса Kotlin 1.2.70 говорит нам о том, что такая конвертация позволит существенно увеличить производительность комплексных операций обработки данных.

В теории это звучит логично, потому что последовательности как раз и были придуманы для ускорения операций обработки коллекций. Они позволяют избавиться от оверхеда, вызванного тем, что такие операции, как filter и map, примененные к спискам, фактически создают новые списки. Но одно дело — теория, а другое — реальная жизнь.

Возьмем два семпла кода обработки списков. Классический код:

list.filter { true }.map { it }.filter { true }.map { it }

И код, использующий конвертацию в последовательности:

list.asSequence()
    .filter { true }.map { it }.filter { true }.map { it }
    .toList()

И протестируем их в разных ситуациях по отношению к разным спискам разной длины.

Результаты, как ни странно, почти одинаковы. Более того, последовательности дают совсем незначительный выигрыш в производительности на коротких списках и существенно проигрывают спискам на очень длинных. Что еще более интересно, если добавить в код небольшую задержку, симулировав реальные вычисления, разница пропадает вовсе.

Есть, однако, две ситуации, в которых последовательности выигрывают с очень большим отрывом: методы find и first. Происходит так потому, что поиск в случае последовательностей останавливается после того, как нужный элемент найден, но продолжается в случае списков.

Результаты теста
Результаты теста

7 новых инструментов разработчика

Lucky 7 new tools and plugins for Android developers & designers — подборка из семи свежих инструментов.

1. adb-enhanced — скрипт-обертка для ADB, существенно расширяющий его возможности. Позволяет, например, включить Doze (режим энергосбережения):

adbe doze on

Отключить передачу данных по мобильным сетям:

adbe mobile-data off

и многое другое.

2. deep-clean — скрипт, удаляющий все временные файлы, использованные при сборке приложения. Может пригодиться, если приложение по какой-то причине не собирается.

3. Android-drawable-preview-plugin — плагин Android Studio, показывающий превью изображений в папке Drawable.

4. Android Input — плагин Android Studio, позволяющий быстро вводить текст в эмулятор.

5. bundletool — официальная утилита Google для работы с Android App Bundle, новым форматом упаковки приложений Android Studio 3.2.

6. GradientDrawableTuner — приложение для генерации и трансформации Drawable.

7. ColorBox — инструмент для подбора цветов.

Превью Drawable
Превью Drawable

Как создать высокопроизводительное приложение на Kotlin

Writing an Android NES Emulator — Performance optimizations — небольшая статья, автор которой рассказывает, как создавал эмулятор NES на Kotlin (ktnes) и какие уроки из этого вынес.

  1. Не стоит вызывать нативные функции (JNI) в основном цикле эмулятора. Из-за необходимости маршалинга и демаршалинга данных JNI-вызовы будут существенно замедлять код.
  2. Аллокации памяти дороги, поэтому их также стоит избегать, а именно избавиться от создания объектов в основном цикле. Стоит иметь в виду, что объекты могут быть созданы неявно, например при проходе по коллекции в цикле; в этом случае будет создан объект класса Iterator.
  3. Стоит подумать о сокращении стека вызовов, другими словами — развернуть последовательность вызовов функций в сплошной последовательный код.

Топ библиотек для Kotlin

What’s in your Larder: Libraries for Kotlin Android development — очередной топ библиотек, в этот раз с акцентом на Kotlin-разработчиков.

1. Kovenant — библиотека асинхронного программирования для Kotlin. По сути, реализация паттерна Promise:

task {
    // some (long running) operation, or just:
    1 + 1
} then { 
    i -> "result: $i"   
} success { 
    msg -> println(msg)
}

2. Picasso — широко известная библиотека для загрузки, обработки и показа изображений. Позволяет сделать все эти действия с помощью одной строки кода:

Picasso.get().load(url).resize(50, 50).centerCrop().into(imageView)

3. Anko — библиотека, упрощающая разработку приложений на языке Kotlin. Кроме набора достаточно простых функций для показа сообщений на экране, включает в себя DSL, позволяющий программировать интерфейс прямо в коде:

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}

4. Fuel — сетевая библиотека, использующая лямбды для обработки ответов, вместо традиционных для других библиотек листенеров.

5. Forge — простой в использовании парсер JSON, разработанный автором Fuel.

6. Result — библиотека, позволяющая вернуть из функции два значения разных типов. Например, Result.Success может содержать значение, если функция отработала правильно и вернула значение, Result.Failure — в случае ошибки.

Observable-поля в Kotlin

Hassle-free listeners with Observable — статья о функции языка Koltin под названием Observable property, которая позволяет выполнить код в момент записи или чтения значения поля.

Ты сразу поймешь, зачем это нужно, если программируешь для Android не первый день: при изменении модели мы сразу можем изменить View. В коде это выглядит так:

class Book {
    var title: String by observable("untitled") { _, oldValue, newValue ->
        // Твой код здесь
    }
}

При изменении названия книги выполняется твой код (очень жизненный пример, да).

У Observable есть антагонист под названием Vetoable. В отличие от Observable Vetoable выполняется не после, а до присвоения значения и может заблокировать присвоение нового значения, если колбэк вернет false. Пример:

class Book {
    var title: String by vetoable("untitled") { _, oldValue, newValue ->
        !newValue.isEmpty()
    }
}

Библиотеки

  • Awesome-Android-Persistence — список библиотек и фреймворков, предназначенных для хранения данных на диске;
  • Cockpit — встраиваемый в приложение инструмент, позволяющий на лету изменять параметры интерфейса;
  • Tink — простая библиотека Google для реализации максимально корректного и безопасного шифрования;
  • PatternLockView — экран для ввода графического ключа, аналогичный экрану блокировки Android;
  • WiseFy — враппер для более удобного управления модулем Wi-Fi;
  • AndroidWM — библиотека для пометки изображений с помощью водяных знаков;
  • CheckableChipView — переключатель в стиле приложения Google I/O 2018;
  • dresscode — библиотека для динамического теминга приложения;
  • StateProgressBar — прогрессбар с отметкой стадий загрузки;
  • Android LoadX — функция-расширение Kotlin, отображающая индикатор загрузки поверх любого View;
  • PowerMenu — простая в использовании библиотека для создания pop-up-меню;
  • InboxRecyclerView — расширяемый список в стиле приложения Inbox;
  • PixelShot — простая библиотека для сохранения любого View в файл;
  • Covert — библиотека для создания swipe actions (действий, вызываемых свайпом элемента в сторону) в списках RecyclerView;
  • download-manager — библиотека для управления длительными загрузками, автоматически возобновляет скачивание файла;
  • AppListManager — библиотека для получения списков установленных приложений и активностей.

Подписывайтесь на наш канал в: Telegram, Vk, Twitter.

Источник: xakep.

Главред

Оставить комментарий