Android Good Reads
Android 16 Preview BAKLAVA Вроде, только-только Android 15 проводили в релиз, а уже выходит следующая версия. План такой: Превью сегодня ➡️ Бета в Январе ➡️Стабильная бета в Марте ➡️ релиз по готовности (Июнь) 👉 Изменения в API можно глянуть тут 👉 Внутри…
Касательно Android 16 DP1, это ведь первый релиз по новой системе ускоренных релизов, верно?
Согласно плану, нас ждёт много нового в средине и в конце года. Новое API и новые
Согласно плану, нас ждёт много нового в средине и в конце года. Новое API и новые
Deprecated
😅. Заранее предупреждают, что лучше настроить CI так, чтобы она гоняла тесты на разных API levels. Кстати, а какой targetSdk у вас сейчас в проекте, следуете рекомендациям от гугла?Полезная библиотека этой недели - https://strikt.io/ (563 ⭐️ )
Устали от
Примеры:
Сильно гибче стандартного функционала. Работает с JUnit5, Minutest и Spek
Устали от
assertTrue(true == true)
? Тогда strikt может упростить вам жизнь!Примеры:
// Flexible assertions about collections
val subject = listOf("Eris", "Thor", "Anubis", "Ra")
expectThat(subject)
.contains("Eris", "Thor", "Anubis")
// “Narrow” the assertion to elements or ranges
expectThat(subject)[0].isEqualTo("Eris")
// Make grouping assertions
val subject = Deity.values().map { it.toString() }
expectThat(subject)
.isNotEmpty()
.any { startsWith("E") }
// Custom assertions are extension functions
fun Assertion.Builder<LocalDate>.isStTibsDay() =
assert("is St. Tib's Day") {
when (MonthDay.from(it)) {
MonthDay.of(2, 29) -> pass()
else -> fail()
}
}
expectThat(LocalDate.of(2020, 2, 29)).isStTibsDay()
Сильно гибче стандартного функционала. Работает с JUnit5, Minutest и Spek
Please open Telegram to view this post
VIEW IN TELEGRAM
Android Good Reads
Kotlin 2.1.0-RC2 Внутри много доработок, но самая важная для меня - стабильная работа в xCode 16+. Я, по-глупости, обновился на macOS Sequoia месяц назад, что потянуло за собой новый xCode, и iOS сборка нашего KMM проекта сломалась на моей ноутбуке. Да…
А вот и релиз!
Кратко:
👉 Новые экспериментальные фичи. Guard условие в
👉 Обновили K2 компилятор и сделали ряд улучшенией в
👉 Для KMM стабилизировали Gradle DSL, много улучшений для Kotlin/Native, Kotlin/Wasm
👉 Поддержка последних версий Android Gradle Plugin
👉 Обновили документацию
Полный список изменений тут
А еще сегодня (28.11) в 7 вечера будет прямая трансляция с разработчиками на тему этого обновления тут
Кратко:
👉 Новые экспериментальные фичи. Guard условие в
when
, break
и continue
не только для своего скоупа. Разбирали частично ---> тут👉 Обновили K2 компилятор и сделали ряд улучшенией в
kapt
👉 Для KMM стабилизировали Gradle DSL, много улучшений для Kotlin/Native, Kotlin/Wasm
👉 Поддержка последних версий Android Gradle Plugin
👉 Обновили документацию
Полный список изменений тут
А еще сегодня (28.11) в 7 вечера будет прямая трансляция с разработчиками на тему этого обновления тут
Хорошая тренировка вместо одинаковых задач на литкоде. А если ваши знакомые хотят попробовать Kotlin, то и отличный интенсив для них
Решаете свой advent of code и хотите посоревноваться? Кидайте ссылки в комменты!
Please open Telegram to view this post
VIEW IN TELEGRAM
Ультимативный гайд по написанию чисто кода на Jetpack Compose
Тут приведу основные идеи для
👉 Именование функций должно быть в PascalCase
👉 Последовательность параметров
Официальная рекомендация Android: Обязательные параметры ->
Более удобная версия:
👉 Либо возвращаем значение из
👉 У каждой функции не более 1 лайаута и при этом она должна быть независимой от места вызова
👉 Каждая функция должна содержать единственный
👉 Старайтесь не держать собственное состояние внутри каждой
👉 Используйте отступы предоставляемые через
Примеры как надо ✅ и как не надо ❌ читаем тут
Тут приведу основные идеи для
@Composable
функции, а то как надо и как не надо можно увидеть внутри статьи:👉 Именование функций должно быть в PascalCase
👉 Последовательность параметров
Официальная рекомендация Android: Обязательные параметры ->
Modifier
-> необязательные параметры -> Вложенная @Composable
Более удобная версия:
Modifier
-> входные данные -> UI параметры -> калбеки -> Вложенная @Composable
👉 Либо возвращаем значение из
@Composable
, либо что-то рисуем. Но не одновременно👉 У каждой функции не более 1 лайаута и при этом она должна быть независимой от места вызова
👉 Каждая функция должна содержать единственный
Modifier
со стандартным значением👉 Старайтесь не держать собственное состояние внутри каждой
@Composable
функции👉 Используйте отступы предоставляемые через
Scaffold
Примеры как надо ✅ и как не надо ❌ читаем тут
Android Good Reads
А вот и релиз! Кратко: 👉 Новые экспериментальные фичи. Guard условие в when, break и continue не только для своего скоупа. Разбирали частично ---> тут 👉 Обновили K2 компилятор и сделали ряд улучшенией в kapt 👉 Для KMM стабилизировали Gradle DSL, много улучшений…
И еще раз про Guard Conditions
👉 Как включить:
1) Проверяем что стоит галочка напротив
2) Добавляем
👉 Без guard conditions:
👉 С guard conditions:
👉 Как включить:
1) Проверяем что стоит галочка напротив
Enable K2 mode
в IDE2) Добавляем
compileOptions
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xwhen-guards")
}
}
👉 Без guard conditions:
when (response) {
is HttpResult.Success -> println("Success")
is HttpResult.Failed -> {
if (response.statusCode == 503) {
println("Maintenance")
} else {
println("Failed with code ${response.statusCode}")
}
}
}
👉 С guard conditions:
when (response) {
is HttpResult.Success -> println("Success")
is HttpResult.Failed if response.statusCode == 503 -> println("Maintenance")
is HttpResult.Failed -> println("Failed with code ${response.statusCode}")
}
JetBrains исследует возможность добавить Hot Reload в Compose
https://github.com/JetBrains/compose-hot-reload (404⭐️ )
Мультиплатформа тоже поддерживается, судя по всему. Для сборки используеть отдельная версия официальных плагинов (
5 минутное видео с демонстрацией от одного из разработчиков
https://github.com/JetBrains/compose-hot-reload (404
Мультиплатформа тоже поддерживается, судя по всему. Для сборки используеть отдельная версия официальных плагинов (
2.1.0-firework.31
) и сам плагин для hot-reload
5 минутное видео с демонстрацией от одного из разработчиков
Please open Telegram to view this post
VIEW IN TELEGRAM
MVI + Jetpack Compose что и как!
Внутри статьи немного теории о том как устроен
👉
👉 Compose навигация
Справедливо заметили, что при таком подходе,
Финальный вид приложения можно посмотреть на GitHub
Внутри статьи немного теории о том как устроен
MVI
(Model
- View
- Intent
) и как он работает.👉
Hilt
, KSP
, Room
и ViewModel
как основа для проекта👉 Compose навигация
Справедливо заметили, что при таком подходе,
ViewModel
должна отвечать только за управление состоянием, а разруливание корутин должно уйти на слой ниже, в репозиторий. Финальный вид приложения можно посмотреть на GitHub
Ищем блокирующие вызовы из неблокирующих потоков
Проверяем приложение на наличие блокирующих вызовов. Они могут вызывать микрофриз, а не краш приложения. С библиотекой BlackHound (1400⭐️ +) вы получите полноценной краш-репорт. Используется вместе с отладочной тулзой для корутин:
Пример:
Краш:
Фикс:
Проверяем приложение на наличие блокирующих вызовов. Они могут вызывать микрофриз, а не краш приложения. С библиотекой BlackHound (1400
org.jetbrains.kotlinx:kotlinx-coroutines-debug
Пример:
import reactor.blockhound.BlockHound
import kotlinx.coroutines.debug.CoroutinesBlockHoundIntegration
import kotlinx.coroutines.*
fun main() {
BlockHound.install(CoroutinesBlockHoundIntegration())
runBlocking {
launch(Dispatchers.Default) {
Thread.sleep(1000) // Краш
}
}
}
Краш:
Exception in thread "main" reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep
at java.base/java.lang.Thread.sleep(Thread.java)
at MainKt$main$1$1.invokeSuspend(Main.kt:12)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Фикс:
import reactor.blockhound.BlockHound
import kotlinx.coroutines.debug.CoroutinesBlockHoundIntegration
import kotlinx.coroutines.*
fun main() {
BlockHound.install(CoroutinesBlockHoundIntegration())
val droidgr = Dispatchers.IO.limitedParallelism(10) // или просто Dispatchers.IO
runBlocking {
launch(droidgr) {
Thread.sleep(1000) // OK
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
Записи докладов с droidcon London 2024 про Compose:
- A Snapshot Preview of Paparazzi 2.0
- Building State Holders in Compose with Molecule: A New Approach to Reusable UI Components
- Crafting Narratives: Shaping TalkBack with Compose Semantics
- Creating a Custom Compose Layout, Step-by-Step
- Cutting-Edge-to-Edge in Android 15: Using Previews and Testing in Jetpack Compose to Manage Insets
- Deep Dive into the Compose Compiler
- Designing scalable Compose APIs
- Hardware development with KMP and Compose Desktop
- Jetpack Compose: Drawing without pain and recomposition
- Navigation in a Multiplatform World: Choosing the Right Framework for your App
- Personalizing Accessibility
- Project Sparkles: how Compose is changing Android Studio
- Streamlining Permission Request in Jetpack Compose
- Tap it! Shake it! Fling it! Sheep it! - The Gesture Animations Dance!
- Text in Compose: Beyond the Basics
- What’s New in Compose Multiplatform - A Live Tour
- Why is adaptive layout a nightmare?
- A Snapshot Preview of Paparazzi 2.0
- Building State Holders in Compose with Molecule: A New Approach to Reusable UI Components
- Crafting Narratives: Shaping TalkBack with Compose Semantics
- Creating a Custom Compose Layout, Step-by-Step
- Cutting-Edge-to-Edge in Android 15: Using Previews and Testing in Jetpack Compose to Manage Insets
- Deep Dive into the Compose Compiler
- Designing scalable Compose APIs
- Hardware development with KMP and Compose Desktop
- Jetpack Compose: Drawing without pain and recomposition
- Navigation in a Multiplatform World: Choosing the Right Framework for your App
- Personalizing Accessibility
- Project Sparkles: how Compose is changing Android Studio
- Streamlining Permission Request in Jetpack Compose
- Tap it! Shake it! Fling it! Sheep it! - The Gesture Animations Dance!
- Text in Compose: Beyond the Basics
- What’s New in Compose Multiplatform - A Live Tour
- Why is adaptive layout a nightmare?
Начиная с версии Android 16 гугл планирует сокращать User-Agent
Итоговое значение будет выглядеть вот так:
Итоговое значение будет выглядеть вот так:
Mozilla/5.0 (Linux; Android 10; K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/125.000 Mobile Safari/537.36
This media is not supported in your browser
VIEW IN TELEGRAM
Android XR SDK Developer Preview
Платформа для расширенной реальности теперь и на Android. Базируется так же, на open source - OpenXR. Все приложения на Android должны быть совместимы
Пощупать в эмуляторах можно тут, доступно для разработки начиная с Android Studio Meerkat
Платформа для расширенной реальности теперь и на Android. Базируется так же, на open source - OpenXR. Все приложения на Android должны быть совместимы
Пощупать в эмуляторах можно тут, доступно для разработки начиная с Android Studio Meerkat
О разработке SDK
Что нужно помнить при работе с SDK, как делать не нужно:
👉 Разработка SDK != разработка клиентского приложения. Например, не стоит перехватывать UI у клиентского приложения, если внутри SDK возникла ошибка. Лучше, прокиньте состояние ошибки и дайте пользователям SDK самим решать как ее отобразить.
👉 Предоставление пользовательского интерфейса через SDK влечет за собой ряд проблем: Отсутствие гибкости, конфликты ресурсов, увеличение размера SDK и сложности в его обслуживании, а так же проблемы масштабируемости. Но если вам все-таки необходимо поставлять UI с SDK, то разделите свое SDK на 2 разных
👉 Минимизируйте внешние зависимости. А если используете - то лучше всего их изолировать. Неприятно ради 1 библиотеки подключать RxJava и Lottie, для конвертации в свой формат. Не забывайте, что не все библиотеки предоставляют лицензию на использование в коммерческих целях, например, GPL лицензии
❗️ Старайтесь избегать глобальных синглтонов. Неприятно, когда в приложении появляется утечка памяти, а я никак не могу на это повлиять, кроме как отказаться от вашего SDK.
👉 Пишите документацию и CHANGELOG
С какими неприятными последствиями спорных решений в SDK вы сталкивались?
Что нужно помнить при работе с SDK, как делать не нужно:
👉 Разработка SDK != разработка клиентского приложения. Например, не стоит перехватывать UI у клиентского приложения, если внутри SDK возникла ошибка. Лучше, прокиньте состояние ошибки и дайте пользователям SDK самим решать как ее отобразить.
👉 Предоставление пользовательского интерфейса через SDK влечет за собой ряд проблем: Отсутствие гибкости, конфликты ресурсов, увеличение размера SDK и сложности в его обслуживании, а так же проблемы масштабируемости. Но если вам все-таки необходимо поставлять UI с SDK, то разделите свое SDK на 2 разных
package
: UI и Core Logic с возможностью их раздельного использования. Не забудьте про Analytics Hooks в UI модуле!👉 Минимизируйте внешние зависимости. А если используете - то лучше всего их изолировать. Неприятно ради 1 библиотеки подключать RxJava и Lottie, для конвертации в свой формат. Не забывайте, что не все библиотеки предоставляют лицензию на использование в коммерческих целях, например, GPL лицензии
👉 Пишите документацию и CHANGELOG
С какими неприятными последствиями спорных решений в SDK вы сталкивались?
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
SDK Development; The Good, The Bad, The Ugly
Or, How to avoid death threats from angry developers
Анонс Koin IDE Plugin
Что позволит делать плагин:
👉 Видеть все дерево зависимостей
👉 Навигация между компонентами
Валидация на уровне Koin делается в рантайме, но через плагин можно проверить валидность состояния с помощью статического анализа. Предварительная дата релиза - 1 квартал 2025
Что позволит делать плагин:
👉 Видеть все дерево зависимостей
👉 Навигация между компонентами
Валидация на уровне Koin делается в рантайме, но через плагин можно проверить валидность состояния с помощью статического анализа. Предварительная дата релиза - 1 квартал 2025
blog.kotzilla.io
Koin IDE Plugin: A Koin Configuration Tree
Introducing the Koin IDE Plugin for Kotlin: See configurations, navigate dependencies, & validate your Koin setup an intuitive tree view. Coming Q1 2025.
Разбираем Low Memory Management в Android: Kswapd & LMK
👉 Память в системе разделяется на RAM, zRAM и Storage(постоянная)
👉 RAM разделяется на Pages по 4KB. Каждый Page может быть used или unused.
used в свою очередь делится на Private, если им владеет только 1 процесс или Shared в ином случае
Так же used Page может быть Clean, если это копия данных из Storage и Dirty если это модифицированные данные
Само управление происходит с помощью двух механизмов:
👉
👉
Чуть подробнее про LMK внутри статьи или в этом видео
👉 Память в системе разделяется на RAM, zRAM и Storage(постоянная)
👉 RAM разделяется на Pages по 4KB. Каждый Page может быть used или unused.
used в свою очередь делится на Private, если им владеет только 1 процесс или Shared в ином случае
Так же used Page может быть Clean, если это копия данных из Storage и Dirty если это модифицированные данные
Само управление происходит с помощью двух механизмов:
👉
kswapd
(kernel swap daemon) Удаляет Clean Pages и восстанавливает копию из хранилища. Сжимает и перемещает Dirty Pages в zRAM. Активируется при нехватки памяти и возвращает все как было, когда процесс, владеющей Page снова оживает.👉
LMK
(Low-memory killer) Удаляет процессы в порядке с приложенной таблицы, тем самым освобождая Pages ими владеющие.Чуть подробнее про LMK внутри статьи или в этом видео
Android Good Reads
Android XR SDK Developer Preview Платформа для расширенной реальности теперь и на Android. Базируется так же, на open source - OpenXR. Все приложения на Android должны быть совместимы Пощупать в эмуляторах можно тут, доступно для разработки начиная с Android…
Android XR KMP
Добавить поддержку Android XR в ваше KMP приложение - легко! Две составляющих:
👉 Добавить зависимость
👉 Добавить
iOS имплементация игнорируется, но предположу, что жизненные циклы достаточно сильно различаются чтобы вписать обе VR/AR платформы сразу
Добавить поддержку Android XR в ваше KMP приложение - легко! Две составляющих:
👉 Добавить зависимость
// shared/build.gradle.kts
sourceSets {
androidMain.dependencies {
implementation(libs.androidx.xr.compose)
implementation(libs.androidx.xr.compose.material3)
implementation(libs.androidx.xr.scenecore)
}
}
👉 Добавить
expect
/ actual
интерфейсыiOS имплементация игнорируется, но предположу, что жизненные циклы достаточно сильно различаются чтобы вписать обе VR/AR платформы сразу
Цикл статей про Mockk и тесты
Не все согласны, что это хороший подход, но существующий и практикующий многими компаниями:
👉 Mockk и основы
👉 Mockk, продвинутое использование. Мокаем статик методы, синглтоны и
👉 Unit-тестирование Android компонентов
👉 Мокаем suspend функции и flow
👉 Пишем поддерживаем и читаемый код в тестах с Mockk
А вы мокаете данные в тестах?
Не все согласны, что это хороший подход, но существующий и практикующий многими компаниями:
👉 Mockk и основы
👉 Mockk, продвинутое использование. Мокаем статик методы, синглтоны и
final
классы👉 Unit-тестирование Android компонентов
👉 Мокаем suspend функции и flow
👉 Пишем поддерживаем и читаемый код в тестах с Mockk
А вы мокаете данные в тестах?
MockK
Provides DSL to mock behavior. Built from zero to fit Kotlin language. Supports named parameters, object mocks, coroutines and extension function mocking
Оптимизируем
Если кратко, то используем key:
Получаем:
👉 Улучшение перфоманса при рекомпозиции
👉 Нормальный контроль над состоянием элементов
Следите чтобы ключи были уникальными!
LazyList
в 1 строчку. Если кратко, то используем key:
LazyColumn {
items(items = yourList, key = { it.id }) { item ->
// Your item UI here
Text(text = item.name)
}
}
Получаем:
👉 Улучшение перфоманса при рекомпозиции
👉 Нормальный контроль над состоянием элементов
Следите чтобы ключи были уникальными!
Medium
Jetpack compose — One Line trick for your ‘LazyColumn’
Make sure you are using this in your Jetpack Compose ‘LazyColumn’
Эволюция архитектурных паттернов
👇 UI-центричная архитектура или
👇
👇
👇
👇
👉 Постепенное упрощение
Внутри статьи примеры с каждым этапом. Кому-то посмотреть как было раньше, кому-то понастольгировать
👇 UI-центричная архитектура или
God Activity
👇
MVC
. Выделили логику в контроллер👇
MVP
. Добавили интерфейсов меж слоями👇
MVVM
. Изоляция UI и реактивщина👇
MVI
и начало эры UDF
👉 Постепенное упрощение
MVI
с дроблением reduce
функции. TEA
, как хороший примерВнутри статьи примеры с каждым этапом. Кому-то посмотреть как было раньше, кому-то понастольгировать
Medium
The Evolution of Android Architecture Patterns: From UI-Centric to MVC to MVP to MVVM to MVI
A time journey through Android’s Architecture Patterns evolution which will leave you with a solid understanding over MVC, MVP, MVVM and…
Шпаргалка по размещению Composable элементов
Подробнее про
Про центрирование и растягивание тут
Подробнее про
Arrangement
с примерами можно глянуть тутПро центрирование и растягивание тут