Android Good Reads
4.05K subscribers
355 photos
15 videos
1 file
2.08K links
Самые интересные статьи, видео и новости, связанные с Android разработкой. Не больше трёх материалов в день.

Автор канала: @Lamprof

Размещение рекламы: @tanyasanovna
Download Telegram
Обновление для часов!

👉 Много обновлений для циферблатов и расширения их функциональности
👉 Watch OS 5 developer preview! - энергоэффективнее и производительнее
👉 Jetpack Compose для Wear OS расширяется и растет. Уже релиз 1.3.1
👉 Блог о том как разработка для Wear OS на Compose позволила писать меньше кода в Soundcloud
👉 Больше инструментов для взаимодействия с часами из Android Studio. В последнем фиче дропе добавили превью для Tiles и ProtoLayout. Появилась возможность подкладывать данные с датчиков для фитнес приложений
Что еще показали?

👉 Анализатор от Google по соблюдению требований безопасности: https://checks.google.com/
👉 Большой апдейт по Compose, но мы уже разбирали его
👉 Вторая бета для Android 15
😅 Android Studio Koala Feature Drop (2024.1.2) Canary 1
👉 Напомнили что Android Automotive OS все еще живет и развивается. Сегодня должен быть доклад

На следующей неделе KotlinConf, ждем больше обновлений по Kotlin оттуда!
Android Good Reads
Coil с поддержкой Compose Multiplatform Вышла Alpha версия Coil 3.0.0 с поддержкой Compose Multiplatform! Wasm таргет будет работать, когда выйдет Ktor с его поддержкой.
Coil(Coroutine Image Loader) поддерживает все платформы с версии 3.0.0-alpha05: Android, JVM, iOS, macOS, Javascript и WASM! Прелесть в том, что не надо под каждую платформу писать свой загрузчик, если вы используете KMP.

Пример использования и того как это выглядит можно глянуть тут
Из приятного:
👉 Контроль над размером выделяемого кэша
👉 Контроль над weak/strong ссылками. Поможет с утечками?
👉 На Android использует стандартные компоненты для загрузки, на остальных платформах собственная обертка над Skia
👉 Миграция с версии 2 выглядит не сложно
Часы. Часы? Часы!

Рекомендации по использованию сторонних фреймворков от разработчицы из Гугла. Даже если не занимаетесь поддержкой wearable девайсов, то интересно глянуть на особенности разработки. Google I/O показал много обновлений для часов!

👉 Сборник Horologist библиотек. Помогают следовать гайдлайнам гугла. Например скорлу или удостовериться что часть элементов не скрыто под скруглением часов
👉 Скриншоты для странички Google Play, чтоб заявить о поддержке часов, даже если нет идеального девайса
👉 Шрифты и Splash screen (Wow!)
👉 Основная дока
Кэширование в Android

Автор рассматривает и предлагает архитектурные решения для следующих типов кэширования:

👉 Cache Only
👉 Network Only
👉 Network First
👉 Cache First - Network Second
👉 Cache First - Network for Later
👉 Cache First - Network Once
✍️ Бонусом, кэширование через networkBoundResource

Выглядит больше как шпаргалка по проектированию кэширования приложения на этапе интервью, но схемы однозначно стоит посмотреть и, возможно, забрать к себе в команду
Please open Telegram to view this post
VIEW IN TELEGRAM
О создании Preview в Jetpack Compose

Как вы подкладываете и обновляете данные для @Preview? В статье предлагается:

👉 Хардкодить данные напрямую
👉 Класть все данные в обьект и подменять в процессе подстановки. А более аккуратный способ — это воспользоваться PreviewParameterProvider (Хорошо описано тут)
👉 Написать полноценный отдельный фабричный метод для описания состояния @Preview. Мне кажется что это оверинжениринг, только если вы не всецело полагаетесь на превью в работе
👉 Использование существующего state holder

У нас в команде решили для каждого UI-класса определять несколько mock() функций с основными кейсами. В итоге у нас есть базовые превью, а при переиспользовании всегда видны возможные коллизии на основных кейсах.
System UI Compatibility and Immersive Status Bar

Разбираемся как в Compose обращаться с областью взаимодействия приложения

👉 enableEdgeToEdge() - растянуть область и забрать контроль у системы
👉 WindowInsets понять область отступа системных компонентов и вставить в padding вашего объекта
👉 Modifier.systemBarsPadding() или Modifier.safeDrawingPadding() сделать тоже самое, но с помощью модификатора
Посмотрите на этот кусочек кода. Выглядит странно, хотя точно используется вашим приложением. Ну а кто транзитивно не использует okio?

Именно с этого момента начинается статья об оптимизации подсчета количества символов в числе. Итоговые результаты такие:
Немного анонсов грядущих изменений в Kotlin. Вероятно, появится объединение типов и ошибок

Более подробно в тикете: kotl.in/f28fo8

Источник
Это не финальный вид, а только предположение о том, как может выглядеть реализация
Сравниваем 2 APK на уровне dex. Не маст-хев инструмент, но посмотреть на сколько хорошо работают ваши proguard правила и сверить apk от релиза к релизу может быть удобно.

Сам инструмент: https://github.com/theapache64/dex-diff
Про новые layout с Google I/O

Новые ContextualFlowRow и ContextualFlowColumn дают чуть больше контроля над элементами, по сравнению со стандартными FlowRow и FlowColumn, хотя они тоже получили небольшое обновление


val items = List(100) { Random.nextFloat() }

ContextualFlowRow(
itemCount = items.size,
maxLines = 3,
maxItemsInEachRow = Int.MAX_VALUE,
horizontalArrangement = Arrangement.Start,
verticalArrangement = Arrangement.Top,
overflow = ContextualFlowRowOverflow.Clip,
modifier = Modifier,
) { index ->
Text(text = items[index].toString())
}


👉 Ключевое изменение в возможности получать index элемента, а так же lineIndex, indexInLine и maxWidthInLine(maxHeightInLine), maxHeight(maxWidthin) из ContextualFlowRowScope(ContextualFlowColumnScope)
👉 Вы могли заметить, что теперь можно указать максимальное количество элементов, а это значит что в элемент можно накинуть на 1 больше элемент чем мы разрешили. Что произойдет? Сработает 1 из 4 overflow policy: Clip, Visible, expandIndicator, expandOrCollapseIndicator, где вам отдается контроль над этими элементами
This media is not supported in your browser
VIEW IN TELEGRAM
Порядок применения модификаторов в Composable компонентах

👉 Хорошая привычка, прописывать Modifier для каждой @Composable функции
👉 Модификаторы применяются в порядке "от конца к началу, изнутри наружу"
👉 Примеры кода в статье
Дебажим зависимости в Gradle!

Гайд о том как дебажить дерево зависимостей проекта на предмет коллизий

👉 Базово построить дерево зависимостей можно, но скорее всего оно будет нечитаемым
./gradlew :app:dependencies > dependencyTree.txt


Добавив --scan, можно посмотреть на аккуратную версию в браузере

👉 Это же дерево зависимостей лучше всего отфильтровать по конфигурации с помощью --configuration. Они бывают: compileClasspath, runtimeClasspath, testCompileClasspath, и testRuntimeClasspath

👉 Найдя проблемную зависимость, разбираем ее с помощью dependencyInsight. Вы увидите как и почему выбирается та или иная версия для проекта.

А что дальше? В статье исключается транзитивная зависимость из одной из библиотек, тем самым решая изначальную проблему конфликта при обновлении фреймворка
Не успели мы перейти на Kotlin 2, как Kotlin 2.0.20-Beta1 приносит новые изменения. Функция copy() для data class будет иметь ту же видимость, что и конструктор. В бета версии пока что покажут warning при использовании
Как будет выглядеть:

data class PositiveInteger private constructor(val number: Int) {
companion object {
fun create(number: Int): PositiveInteger? = if (number > 0) PositiveInteger(number) else null
}
}

fun main() {
val positiveNumber = PositiveInteger.create(42) ?: return
// Будет вызывать Warning в 2.0.20-Beta1
val negativeNumber = positiveNumber.copy(number = -1)
// warning: non-public primary constructor is exposed via the generated 'copy()' method of the 'data' class.
}

Используете ли вы приватный конструктор у data классов?
Появились записи с KotlinConf, разбитые на части:
https://kotlinconf.com/talks/

Особенно хочется отметить моих коллег, которые рассказали как устроено наше кросплатформенное приложение (KMM + Compose). Зацените, будет интересно: https://kotlinconf.com/talks/584799/
This media is not supported in your browser
VIEW IN TELEGRAM
Спустя 4 года в беклоге, фича с заполнением обязательных параметров готова и будет доступна в IDEA 2024.2 EAP. До Android Studio докатится значительно позже.

Мне этого функционала очень давно не хватает
Сегодня разберем частый и не очевидный паттерн - fake interface constructor.
Как выглядит:

interface Foo {
fun foo()
}

fun Foo(): Foo = object : Foo {
override fun foo() {
println("foo")
}
}

fun main() {
val foo: Foo = Foo()
foo.foo()
}


Таким образом предоставляется только интерфейс наружу. Kotlin команда часто так делает, например Job, CoroutineScope, CompletableDeferred, Channel, Mutex, Semaphore, MutableStateFlow, MutableSharedFlow, List именно так и реализованы. При инициализации вы обращаетесь к функции, что, например, сказывается на подсветке синтаксиса в IDE (вызов функции, а не обращение к конструктору)

Зачем?
Это дает свободу разработчикам подменять класс реализации без сложной и ломающей все миграции.
Из книги Marcin Moskała, Effective Kotlin
Что быстрее и в каких задачах. Корутины, RxJava или Executor!

👉 Большой анализ с помощью Jetpack Microbenchmark.
👉 Автор исследует как работают инструменты на единственном потоке, на максимальном количестве потоков исполняемых параллельно и на количестве потоков, равное количеству задач.
👉 Наглядно видно, почему стоит использовать встроенные IO диспатчеры для задач связанных с записью данных
👉 Автор приходит к выводу что лучше использовать малое количество потоков, дробя большую задачу на подзадачи, для быстрого выполнения

Код, соответсвующий результатам на графике, приведен ниже. Автор так же делает сравнительный анализ для каждой операции, так что рекомендую глянуть статью целиком!



private fun mixed(seed: Int): Int {
return when {
seed % 5 == 0 -> network(seed)
seed % 3 == 0 -> storage(seed)
seed % 2 == 0 -> listsManipulation(seed)
else -> arithmetic(seed)
}
}