Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍4❤3👎1
🔥 Compose Hot Reload 1.0.0 — стабильный релиз!
JetBrains выпустили стабильную версию Compose Hot Reload, и это действительно круто!
Теперь когда меняете код Compose UI → жмете Cmd+S/Ctrl+S → изменения мгновенно применяются в запущенном приложении. Без перезапуска. Без потери state.
Можно добавлять/удалять функции, классы, параметры — практически любые изменения кода работают.
✅ Стабильная версия 1.0.0 — больше не beta
✅ Отдельный плагин НЕ нужен — встроен в Compose Multiplatform 1.10+, работает из коробки (zero configuration)
⚠️ Работает только на JVM Desktop — и вот почему это важно понять:
Почему только JVM Desktop?
Hot Reload требует JetBrains Runtime с DCEVM (Dynamic Code Evolution VM). Обычная JVM умеет перезагружать только тела методов. DCEVM может делать произвольные изменения кода — добавлять поля в классы, менять иерархию, интерфейсы и т.д.
Android и iOS не могут использовать JetBrains Runtime с DCEVM. Поэтому Hot Reload технически невозможен на этих платформах.
💡 Зачем это мобильным разработчикам?
Еще один повод добавить Desktop таргет в ваш KMP проект!
Даже если вы не планируете запускать Desktop версию в прод - это мощный инструмент для разработки:
👉 Быстро итерируете UI на Desktop с Hot Reload
👉 Проверяете изменения
👉 Переносите на Android/iOS
Скорость итераций UI вырастает в разы. Вместо "изменил → собрал → запустил → дождался" получается "изменил → Cmd+S → увидел результат".
Короче: если делаете Compose Multiplatform — попробуйте обязательно. Desktop таргет окупится только ради Hot Reload.
🔗 Подробности в блоге JetBrains и в документации
#Compose #KMP #Desktop #JVM #CMP
JetBrains выпустили стабильную версию Compose Hot Reload, и это действительно круто!
Теперь когда меняете код Compose UI → жмете Cmd+S/Ctrl+S → изменения мгновенно применяются в запущенном приложении. Без перезапуска. Без потери state.
Можно добавлять/удалять функции, классы, параметры — практически любые изменения кода работают.
✅ Стабильная версия 1.0.0 — больше не beta
✅ Отдельный плагин НЕ нужен — встроен в Compose Multiplatform 1.10+, работает из коробки (zero configuration)
⚠️ Работает только на JVM Desktop — и вот почему это важно понять:
Почему только JVM Desktop?
Hot Reload требует JetBrains Runtime с DCEVM (Dynamic Code Evolution VM). Обычная JVM умеет перезагружать только тела методов. DCEVM может делать произвольные изменения кода — добавлять поля в классы, менять иерархию, интерфейсы и т.д.
Android и iOS не могут использовать JetBrains Runtime с DCEVM. Поэтому Hot Reload технически невозможен на этих платформах.
💡 Зачем это мобильным разработчикам?
Еще один повод добавить Desktop таргет в ваш KMP проект!
Даже если вы не планируете запускать Desktop версию в прод - это мощный инструмент для разработки:
👉 Быстро итерируете UI на Desktop с Hot Reload
👉 Проверяете изменения
👉 Переносите на Android/iOS
Скорость итераций UI вырастает в разы. Вместо "изменил → собрал → запустил → дождался" получается "изменил → Cmd+S → увидел результат".
Короче: если делаете Compose Multiplatform — попробуйте обязательно. Desktop таргет окупится только ради Hot Reload.
🔗 Подробности в блоге JetBrains и в документации
#Compose #KMP #Desktop #JVM #CMP
👍28🔥8👎3❤1
Landscapist — это модульная библиотека для загрузки изображений, построенная специально для Compose. В отличие от монолитных решений, она предлагает гибкую архитектуру с поддержкой различных движков загрузки: Glide, Coil и Fresco.
Ключевые фичи:
👉 Compose Multiplatform из коробки. Библиотека изначально проектировалась для работы на Android, iOS, Desktop и Web. Один API для всех платформ.
👉 Модульная архитектура. Вы подключаете только то, что нужно. Core-модуль весит минимум, а специфичные функции (placeholder, эффекты, анимации) добавляются отдельными зависимостями.
👉 Декларативные модификаторы. Все возможности библиотеки доступны через Compose-модификаторы, что делает код чище и понятнее.
👉 Продвинутая обработка состояний. Встроенная поддержка loading, success, failure с возможностью кастомизации под каждое состояние.
👉 Эффекты и анимации. Circular Reveal, crossfade, shimmer-эффект — всё это доступно out-of-the-box.
👉 Palette API. Автоматическое извлечение цветовой палитры из изображения для создания адаптивного UI.
suspend fun loadImage(url: String) {
val request = ImageRequest.builder()
.model(url)
.size(width = 800, height = 600)
.build()
landscapist.load(request).collect { result ->
when (result) {
is ImageResult.Loading -> {
println("Loading...")
}
is ImageResult.Success -> {
val imageBitmap = result.data
val dataSource = result.dataSource // MEMORY, DISK, or NETWORK
println("Loaded from: $dataSource")
}
is ImageResult.Failure -> {
val error = result.reason
println("Error: ${error.message}")
}
}
}
}📃 Документация
#Compose
Please open Telegram to view this post
VIEW IN TELEGRAM
👍38❤5👎4🤔2
Forwarded from Android Live 🤖
Styles API в Jetpack Compose 🚀
Интересного завезли. В Compose появился экспериментальный API для работы со стилями, который делает их изменение гораздо удобнее.
Сейчас работа с динамическими стилями требует немало ручного труда. И хотя
Ниже приведён пример кнопки, которая меняет цвет при состояниях
Выглядит неплохо, посмотрим, что будет дальше. Детали тут.
Интересного завезли. В Compose появился экспериментальный API для работы со стилями, который делает их изменение гораздо удобнее.
Сейчас работа с динамическими стилями требует немало ручного труда. И хотя
InteractionSource неплохо приспособлен для этих задач, Styles API упрощает процесс в разы.Ниже приведён пример кнопки, которая меняет цвет при состояниях
hovered и pressed.
@Composable
fun InteractiveButton(onClick: () -> Unit) {
ClickableStyleableBox(
onClick = onClick,
style = {
background(Color.Green)
size(150.dp)
hovered { animate { background(Color.Yellow) } }
pressed { animate { background(Color.Red) } }
}
)
}
Выглядит неплохо, посмотрим, что будет дальше. Детали тут.
Dove Letter
Introducing the Experimental Styles API in Jetpack Compose
Explore the new experimental Styles API in Jetpack Compose. Learn how to create reusable, composable styling patterns for your Android UI components.
❤24🔥13👍4👎2
This media is not supported in your browser
VIEW IN TELEGRAM
Анимация смены темы реализована через перехват отрисовки в Modifier.Node: сначала делается снимок UI в старой теме, затем тема переключается, фиксируется новое состояние и запускается анимация между двумя скриншотами. Переход рисуется как круговое раскрытие новой темы, что позволяет избежать мерцаний и добиться плавного эффекта.
#Compose #Анимация
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥87👍11❤5👎5
This media is not supported in your browser
VIEW IN TELEGRAM
Вышел крупный релиз плагина для Android Studio. Две главные фичи:
👉 Recomposition Cascade Visualizer
Правый клик на любой @Composable → "Analyze Recomposition Cascade" — и получаешь дерево всех downstream-компонентов, которые будут перерисованы. Для каждого показывается статус (skippable / non-skippable), общая статистика и максимальная глубина. Двойной клик по узлу — переход к исходнику. Работает с защитой от циклов и ограничением глубины до 10 уровней.
👉 Live Recomposition Heatmap
Прямо в редакторе, над каждой composable-функцией, в реальном времени отображается количество рекомпозиций с подключённого устройства через ADB. Цветовая индикация:
🟢 < 10 — всё ок
🟡 10–50 — стоит присмотреться
🔴 50+ — проблема
Данные читаются из TraceRecomposition событий logcat. Поддерживается несколько устройств одновременно.
#Compose #Performance
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤53👍17👎4🔥3🤔3
Forwarded from Aurora Developers (Vitaliy Zarubin)
🔥 Compose Multiplatform доступен на ОС Аврора!
Отличные новости для Kotlin-сообщества и всех, кто интересуется российской мобильной разработкой. Теперь вы можете создавать приложения для ОС Аврора, используя современный и привычный инструментарий — Kotlin и Compose Multiplatform.
Что опубликовано:
В репозитории на mos.hub выложены компоненты, необходимые для разработки:
- Проекты Compose Multiplatform для сборки.
- Готовые артефакты в репозитории Aurora Maven.
- Плагин для Gradle, упрощающий сборку приложений.
Что дальше?
В планах — расширение поддержки платформы и стабилизация проекта. А уже сейчас в документации вы найдете подробное руководство по началу работы, а также два демонстрационных приложения, которые помогут быстро разобраться с особенностями платформы.
👉 Документация
Хотите помочь проекту стать лучше?
Присоединяйтесь к разработке на mos.hub! Мы открыты к вашему коду и экспертизе. Только #ВМЕСТЕ мы сможем сделать инструмент максимально полезным для всего сообщества.
👉 Репозиторий
Отличные новости для Kotlin-сообщества и всех, кто интересуется российской мобильной разработкой. Теперь вы можете создавать приложения для ОС Аврора, используя современный и привычный инструментарий — Kotlin и Compose Multiplatform.
Что опубликовано:
В репозитории на mos.hub выложены компоненты, необходимые для разработки:
- Проекты Compose Multiplatform для сборки.
- Готовые артефакты в репозитории Aurora Maven.
- Плагин для Gradle, упрощающий сборку приложений.
Что дальше?
В планах — расширение поддержки платформы и стабилизация проекта. А уже сейчас в документации вы найдете подробное руководство по началу работы, а также два демонстрационных приложения, которые помогут быстро разобраться с особенностями платформы.
👉 Документация
Хотите помочь проекту стать лучше?
Присоединяйтесь к разработке на mos.hub! Мы открыты к вашему коду и экспертизе. Только #ВМЕСТЕ мы сможем сделать инструмент максимально полезным для всего сообщества.
👉 Репозиторий
👎49🔥32🤔8👍4❤3
Forwarded from Vitaliy Zarubin | @keygenqt
Please open Telegram to view this post
VIEW IN TELEGRAM
👎44👍27🤔3
Forwarded from Android Broadcast
🤯 Конец Android View ближе чем кажется - в будущей версии Android Studio убирают поддержку превью для Custom View.
Источник - сайт Android Developers
#Android #AndroidDev #Compose #AndroidStudio
Источник - сайт Android Developers
#Android #AndroidDev #Compose #AndroidStudio
👍60🤯42👎18🔥13🎉11🏆1
Мэтт МакКенна выпустил библиотеку, которая превращает рекомпозиции в обычные test assertions. Dejavu решает проблемы постоянного мониторинга за рекомпозияцими без изменений в продакшн-коде — только
Modifier.testTag(), который скорее всего у вас уже есть:// Пример теста
@get:Rule
val composeTestRule = createRecompositionTrackingRule()
@Test
fun incrementCounter_onlyValueRecomposes() {
composeTestRule.onNodeWithTag("inc_button").performClick()
composeTestRule.onNodeWithTag("counter_value")
.assertRecompositions(exactly = 1)
composeTestRule.onNodeWithTag("counter_title")
.assertStable() // ноль рекомпозиций
}
Когда тест падает, получаете структурированный отчёт:
UnexpectedRecompositionsError: testTag='product_header'
Composable: demo.app.ui.ProductHeader (ProductList.kt:29)
Expected: exactly 0 recomposition(s)
Actual: 1 recomposition(s)
All tracked composables:
ProductListScreen = 1
ProductHeader = 1 <-- FAILED
ProductItem = 1
Recomposition timeline:
#1 at +0ms — param slots changed: [1] | parent: ProductListScreen
Possible cause:
1 state change(s) of type Int
Parameter/parent change detected (dirty bits set)
Видно какой composable, сколько раз рекомпозировался и почему. Под капотом используется
CompositionTracer API из compose-runtime 1.2.0, никаких Gradle-плагинов и байткод-манипуляций. Запускается как instrumented тест.#Android #AndroidDev #Compose #JetpackCompose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥46👏7❤5👎4🤔2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Наткнулся на отличный разбор от ребят из Т-Банка — они переписывали главный экран с XML+View на Compose и столкнулись с проблемой, которую многие, думаю, обходят стороной.
Суть: есть
LazyColumn, в нём элемент с animateContentSize(). Когда элемент расширяется по высоте, нижние карточки не успевают сместиться в такт — небольшой, но заметный рассинхрон.Казалось бы — поменяй
spring на tween, синхронизируй тайминги и готово. Спойлер: нет.1️⃣ Замена на линейный
tween — разницы визуально почти ноль. Скорость placementSpec тоже не влияет на смещение нижних айтемов при ресайзе верхнего.2️⃣ Установка
placementSpec = null — синхронизация появляется, но полностью ломает анимацию перемещения айтемов. Не вариант.3️⃣ Попытка написать свой модификатор — обречена с самого начала.
LazyLayoutAnimationSpecsNode помечен как internal, а внутренний LazyLayoutItemAnimator, который реально управляет анимациями, недоступен снаружи. Скопировать код не выйдет — каст по типу вернёт null, и вся механика рассыпается. Форкать 5000+ строк LazyColumn — очевидно нет.Самое интересное — анимация удаления при кастомной реализации не работает в принципе: к моменту
DisposableEffect.onDispose элемент уже удалён из дерева. А стандартный animateItem работает на уровне layout-фазы и может буквально «удерживать» элемент в дереве до окончания анимации.Итог у команды — оставили
RecyclerView для списка, айтемы внутри на Compose. Костыль, но рабочий, пока Google не откроет нужные API. Issue уже создан, подписывайтесь если сталкивались.Я лично не сталкивался с таким кейсом в продакшне, но статья хорошо показывает, где у Compose сейчас реальные границы расширяемости и что без View пока никуда.
#Android #Compose #AndroidDev #JetpackCompose #Анимация
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥33👎13❤8👍2
Одна из моих любимых тем в Compose-разработке — отладка рекомпозиций. Layout Inspector, Rebugger, ComposeInvestigator — всё это хорошие инструменты, но у них общий слепой угол: они говорят сколько рекомпозиций, но не отвечают на вопрос нормально ли это для данного компонента.
HomeScreen, который рекомпозируется 10 раз в секунду — это проблема. Анимация, которая делает то же самое — это норма. Число одинаковое, вывод противоположный.Библиотека работает на основе Kotlin compiler plugin, который классифицирует каждый
@Composable по роли и назначает ему бюджет рекомпозиций:1️⃣ Screen — 3/s. Если экранный компонент рекомпозируется чаще, state утекает вверх по дереву
2️⃣ Leaf — 5/s.
Text, Icon, Image — дёшевы сами по себе, но не должны «молотить»3️⃣ Animated — 120/s. Всё, что использует
animate*, Transition, Animatable — пусть работает4️⃣ Container — 10/s, Interactive — 30/s, List Item — 60/s
При скролле бюджеты удваиваются, при анимации и вводе — умножаются на 1.5. Контекст учитывается.
Когда что-то выходит за рамки, в логах появляется не просто число, а конкретика:
BUDGET VIOLATION: ProfileHeader rate=11/s exceeds LEAF budget=5/s
-> params: avatarUrl=CHANGED, displayName=CHANGED
-> forced: 0 | param-driven: 11 | interaction: IDLE
@Composable. Никакого переключения контекста.Попробую на своих проектах (только не отправляй в прод) — идея с контекстными бюджетами кажется мне намного честнее, чем единый порог для всех компонентов. Решение пока не достигло версии 1.0 но это и некритично, так как не влияет на продакшен код.
🔗 Источник: adital.dev
#Android #Compose #AndroidDev #Производительность
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤49👍13👎8
Media is too big
VIEW IN TELEGRAM
Tracey записывает все жесты, переходы между экранами и кастомные события в кольцевой буфер — и при краше сохраняет его для воспроизведения. Видишь не просто стектрейс, а весь путь пользователя до момента падения.
Не сразу понял куда её применить, но пришла идея интеграции в флоу автоматического прокликивания экрана:
Разрабатываешь фичу локально, кликаешь руками, что-то идёт не так. Вместо того чтобы объяснять разработчику или агенту на словах "я нажал сюда, потом перешёл туда, потом кнопка не сработала" — просто скидываешь ему дамп сессии из Tracey. Он сам восстанавливает картину и сразу работает с контекстом, а не с твоим пересказом.
Структурированный контекст для дебаг-сессии с агентом, чтобы дать четкую информацию.
Библиотека на версии 0.0.2, только вышла, в продакшен пока не потащу. Но для этапа разработки и связки с AI-агентами идея выглядит рабочей.
#Compose #Android #AndroidDev
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👎5👍3
Да, у нас уже есть Jetpack Navigation 3 с официальной поддержкой KMP. Тем не менее авторы Kompass смотрят на проблему иначе, и идея тут любопытная.
Суть в том, что вся навигация строится на чистых редукторах. Любой переход — это
State + Command → State, без побочных эффектов. Вот как это выглядит в коде:// Граф описывает, какие экраны в нём живут и как рендерятся
class MainNavigationGraph : NavigationGraph {
override fun canResolveDestination(id: String) =
id in setOf("home", "profile")
@Composable
override fun Content(entry: BackStackEntry, destination: Destination, navController: NavController) {
when (destination) {
is MainDestination.Home -> HomeScreen(navController)
is MainDestination.Profile -> ProfileScreen(navController)
}
}
}
// Хост принимает список графов и рендерит текущий экран
@Composable
fun AppNavigation() {
val navController = rememberNavController(
startDestination = MainDestination.Home
)
KompassNavigationHost(
navController = navController,
graphs = persistentListOf(MainNavigationGraph())
)
}
// Навигация из экрана
navController.navigate(
entry = BackStackEntry(destinationId = "profile", scopeId = newScope())
)
// Возврат с результатом
navController.pop(result = ProfileResult(userId = "123"))
NavigationState и BackStackEntry иммутабельны, поэтому всю навигацию можно покрыть обычными unit-тестами без инструментации: создаёшь NavigationHandler, кидаешь команду, проверяешь стейт.Особенности:
👉 Таргеты — Android, iOS, Desktop (JVM).
👉 Scopes вместо ViewModel.
rememberScoped<T> живёт ровно пока BackStackEntry в стеке, автоматически чистится при pop.👉 Multi-graph. Несколько независимых графов с собственными лейаутами. Из коробки есть поддержка master-detail для планшетов.
👉 Дип-линки. Через
DeepLinkHandler — типизированный парсинг URI в NavigationCommand.🛠 Библиотека ещё в активной разработке
#KMP #ComposeMultiplatform #Navigation #Kotlin #AndroidDev
Please open Telegram to view this post
VIEW IN TELEGRAM
👎30👍9