Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍38🔥11
С выходом Kotlin 2.3.0 (на момент написания поста вышла Beta 2) компилятор Compose начал генерировать mapping файлы для стектрейсов Composable функций — теперь даже если ваше приложение минифицировано R8, вы сможете понять, где именно упала композиция.
Раньше подробные стектрейсы были доступны только в debuggable сборках из-за того что информация не затиралась. Теперь же появился новый режим —
Group Keys, который позволяет связать анонимные функции из минифицированного кода с исходными @Composable без необходимости хранить пути к файлам.Чтобы включить этот режим, добавьте строку до инициализации любого контента Compose (лучше всего в рутовой функции):
Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.GroupKeys)
После этого при падениях во время composition / measure / draw Compose сам добавит свой стектрейс — даже в релизных сборках 🔥
Для работы требуется:
Если же увидите новые предупреждения или недостаток информации — Google просит репортить их в Issue Tracker.
#compose #kotlin #android #r8
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥28👍4❤3
Тех стек:
👉 Многомодульная архитектура
👉 Metro DI
👉 Coil для показа картинок
👉 Kotlin Coroutines и SerlializationX
👉 Ktor
👉 Jetpack Room
#compose #cmp #kmp #android #ios #desktop #пример #opensource
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🔥6❤3
Обновляйте зависимости или сразу всё через BOM файл:
dependencies {
implementation(
platform("androidx.compose:compose-bom-beta:2025.11.00")
)
}#compose #android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Text(
text = "Solid Shadow",
modifier = Modifier
.shadowGlow(
color = Color.Black.copy(alpha = 0.5f),
borderRadius = 8.dp,
blurRadius = 10.dp,
offsetX = 4.dp,
offsetY = 4.dp
)
.background(Color.White)
.padding(16.dp)
)
#compose #android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍34
Традиционно измерение и кэширование текста происходит на UI-потоке, что для длинных текстов может создавать задержки. Начиная с версии 1.9, Compose позволяет вынести эти операции в фоновый поток. Для View уже давно была такая возможность, а вот на Compose ждали.
Как это работает на практике:
val textMeasurementExecutor = Executors.newSingleThreadExecutor()
CompositionLocalProvider(
LocalBackgroundTextMeasurementExecutor provides DefaultTextMeasurementExecutor
) {
// Весь текст внутри будет предзагружаться в фоне
Column {
Text("Заголовок")
Text("Длинный описательный текст...")
AnnotatedString("Форматированный текст")
}
}
Ключевые преимущества:
- Ускорение layout — предзаполнение word-cache происходит заранее
- Разгрузка UI-потока — тяжелые операции с текстом уходят в фон
- Особенно эффективно в списках (LazyColumn/LazyRow) с текстовым контентом
- Работает с любыми текстовыми компонентами — BasicText, Text, AnnotatedString
Когда стоит применять:
- Приложения с большими объемами текста (читалки, новости, документация)
- Списки с множеством текстовых элементов
- Сложные текстовые интерфейсы с форматированием
❗️Важный нюанс: Результаты могут варьироваться в зависимости от контента, поэтому всегда тестируйте производительность до и после внедрения.
Уже используете эту возможность? Делитесь результатами в комментариях!
#Compose #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
❤31👍10🔥4
🔥 Remote Compose — новый взгляд на Server-Driven UI в Jetpack Compose
В AndroidX Jetpack появилась новая экспериментальная библиотека
Remote Compose позволяет создавать и рендерить интерфейсы Jetpack Compose удалённо, без пересборки и релиза приложения.
UI генерируется на сервере, сериализуется в компактный бинарный документ и воспроизводится на устройстве.
Remote Compose открывает возможности, которые раньше требовали релиза приложения:
⚡️ Мгновенные A/B-тесты — вариации интерфейса меняются на сервере, без обновлений.
🎨 Обновление дизайна в реальном времени — карточки товаров, баннеры, сезонные темы.
📰 Динамические контентные экраны — новости, акции, спецпроекты, которые появляются мгновенно.
🧪 Фичи без мусора — нет необходимости тянуть все варианты экрана в бинарник.
Архитектура Remote Compose состоит из двух частей:
1️⃣ Создание документа
На сервере вы пишете обычные composable-функции — либо используете специальные Remote* элементы (RemoteColumn, RemoteText и др.).
Библиотека перехватывает draw-операции Compose и превращает UI в бинарный документ. Получается самодостаточный «UI-файл», который можно отправить на клиент.
2️⃣ Воспроизведение документа
На устройстве этот документ «проигрывается» плеером:
👉 есть Compose-плеер — для современных приложений;
👉 есть Android View-плеер — для старых архитектур.
Плеер интерпретирует более 90 низкоуровневых операций (рисование, layout, модификаторы, state), обеспечивая реальную нативную отрисовку, без WebView и без компонентов, которые нужно заранее описывать в приложении.
Почему это лучше JSON или WebView
❌ JSON-подход требует схем, ограничивает сложные эффекты, анимации и кастомные компоненты.
❌ WebView — это отдельный процесс, разная визуальная стилистика, тяжёлое потребление памяти и уязвимости
Remote Compose передаёт не структуру компонентов, а реальные команды рисования. Поэтому любое, самое сложное Compose-UI — будет воспроизведено точно так, как вы его задали.
Базовые принципы Remote Compose
👉 Документность — UI становится бинарным документом, который можно кешировать, версионировать, отправлять по сети.
👉 Платформенная независимость — один документ можно рендерить на телефоне, планшете, складном устройстве и даже часах.
👉 Отделение визуального уровня от логики — клиенту не нужно знать о ваших composable-функциях, ViewModel, DI и т.п.
👉 Двусторонняя связь — клики и события возвращаются на клиент, который решает, что делать (навигировать, логировать, изменять состояние).
👉 Поддержка анимаций и выражений — значения могут вычисляться по времени, переменным, условиям.
Для большинства приложений оптимальная модель — гибридная:
📱 основная навигация + критические экраны в “локальном Compose”,
⚙️ динамические зоны — через Remote Compose.
Если Remote Compose будет развиваться так же активно, как Compose в своё время, это может стать стандартом для динамических интерфейсов на Android. Как вам такой поворот с Compose?
Источник тут
#jetpack #android #compose #serverdrivenui #sdui #bdui
В AndroidX Jetpack появилась новая экспериментальная библиотека
androidx.compose.remote (пока еще даже на dev версия). Она предлагает совершенно другой подход к динамическим интерфейсам и может радикально изменить то, как мы обновляем UI в продакшене, категорически отличающаяся от текущих BDUI/SDUI решений.Remote Compose позволяет создавать и рендерить интерфейсы Jetpack Compose удалённо, без пересборки и релиза приложения.
UI генерируется на сервере, сериализуется в компактный бинарный документ и воспроизводится на устройстве.
Remote Compose открывает возможности, которые раньше требовали релиза приложения:
⚡️ Мгновенные A/B-тесты — вариации интерфейса меняются на сервере, без обновлений.
🎨 Обновление дизайна в реальном времени — карточки товаров, баннеры, сезонные темы.
📰 Динамические контентные экраны — новости, акции, спецпроекты, которые появляются мгновенно.
🧪 Фичи без мусора — нет необходимости тянуть все варианты экрана в бинарник.
Архитектура Remote Compose состоит из двух частей:
1️⃣ Создание документа
На сервере вы пишете обычные composable-функции — либо используете специальные Remote* элементы (RemoteColumn, RemoteText и др.).
Библиотека перехватывает draw-операции Compose и превращает UI в бинарный документ. Получается самодостаточный «UI-файл», который можно отправить на клиент.
2️⃣ Воспроизведение документа
На устройстве этот документ «проигрывается» плеером:
👉 есть Compose-плеер — для современных приложений;
👉 есть Android View-плеер — для старых архитектур.
Плеер интерпретирует более 90 низкоуровневых операций (рисование, layout, модификаторы, state), обеспечивая реальную нативную отрисовку, без WebView и без компонентов, которые нужно заранее описывать в приложении.
Почему это лучше JSON или WebView
❌ JSON-подход требует схем, ограничивает сложные эффекты, анимации и кастомные компоненты.
❌ WebView — это отдельный процесс, разная визуальная стилистика, тяжёлое потребление памяти и уязвимости
Remote Compose передаёт не структуру компонентов, а реальные команды рисования. Поэтому любое, самое сложное Compose-UI — будет воспроизведено точно так, как вы его задали.
Базовые принципы Remote Compose
👉 Документность — UI становится бинарным документом, который можно кешировать, версионировать, отправлять по сети.
👉 Платформенная независимость — один документ можно рендерить на телефоне, планшете, складном устройстве и даже часах.
👉 Отделение визуального уровня от логики — клиенту не нужно знать о ваших composable-функциях, ViewModel, DI и т.п.
👉 Двусторонняя связь — клики и события возвращаются на клиент, который решает, что делать (навигировать, логировать, изменять состояние).
👉 Поддержка анимаций и выражений — значения могут вычисляться по времени, переменным, условиям.
Для большинства приложений оптимальная модель — гибридная:
Если Remote Compose будет развиваться так же активно, как Compose в своё время, это может стать стандартом для динамических интерфейсов на Android. Как вам такой поворот с Compose?
Источник тут
#jetpack #android #compose #serverdrivenui #sdui #bdui
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥111🤯44❤21🤔4👍3
// Пример создания документа на севере
val document = captureRemoteDocument(
context = context,
creationDisplayInfo = displayInfo,
profile = profile
) {
RemoteColumn(modifier = RemoteModifier.fillMaxSize()) {
RemoteText("Dynamic Content")
RemoteButton(onClick = { /* action */ }) {
RemoteText("Click Me")
}
}
}
// Пример воспроизведения документа на клиенте
@Composable
fun DynamicScreen(document: CoreDocument) {
RemoteDocumentPlayer(
document = document,
documentWidth = screenWidth,
documentHeight = screenHeight,
modifier = Modifier.fillMaxSize(),
onNamedAction = { name, value, stateUpdater ->
// Обработка именнового действия из документа
when (name) {
"addToCart" -> cartManager.addItem(value)
"navigate" -> navController.navigate(value)
"trackEvent" -> analytics.logEvent(value)
}
},
bitmapLoader = rememberBitmapLoader() // Для загрузки картинок
)
}
Источник тут
#jetpack #android #compose #serverdrivenui #sdui #bdui
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯36👍8🔥2🤔1
👉 Стабильное API Shared Transition
👉 Оптимизированный скролл
👉 Новые подходы к сохранению данных при пересоздании Activity через ViewModel
🚀 Повышена производительность UI на Compose
🛠 Исправлено багов и шероховатостей
Изменений действительно много — в один пост всё не поместить.
Буду разбирать ключевые обновления по отдельности в следующих публикациях на @compose_broadcast ✨
#compose #android
Please open Telegram to view this post
VIEW IN TELEGRAM
❤21👍3
🎭 Динамическое управление shared element анимациями в Compose
В Compose 1.10.0 вы можете динамически включать и отключать анимации shared element в зависимости от условий навигации или состояния UI. Это особенно полезно, когда нужно анимировать переход только в определенных сценариях.
Раньше
⚠️ Важно: По умолчанию, если shared element отключается во время анимации, текущая анимация завершается до удаления элемента. Это предотвращает резкие обрывы.
Новая фича даёт разработчикам больше контроля над анимациями, делая интерфейсы более предсказуемыми и оптимизированными.
#Compose #AndroidDev #Анимация #UI
В Compose 1.10.0 вы можете динамически включать и отключать анимации shared element в зависимости от условий навигации или состояния UI. Это особенно полезно, когда нужно анимировать переход только в определенных сценариях.
Раньше
sharedElement() и sharedBounds() автоматически анимировали изменения layout при нахождения совпадению по ключу. Теперь можно контролировать эту анимацию через конфигурацию SharedContentConfig.
// отим анимировать переход только с экрана A на экран B, но не обратно
SharedTransitionLayout {
val transition = updateTransition(currentState)
transition.AnimatedContent { targetState ->
// Конфигурация, зависящая от состояния
fun animationConfig(): SharedTransitionScope.SharedContentConfig {
return object : SharedTransitionScope.SharedContentConfig {
override val SharedTransitionScope.SharedContentState.isEnabled: Boolean
get() = transition.currentState == "A" &&
transition.targetState == "B"
}
}
...
}
}
⚠️ Важно: По умолчанию, если shared element отключается во время анимации, текущая анимация завершается до удаления элемента. Это предотвращает резкие обрывы.
Новая фича даёт разработчикам больше контроля над анимациями, делая интерфейсы более предсказуемыми и оптимизированными.
#Compose #AndroidDev #Анимация #UI
👍9
Разработчик из ПСБ поделился опытом создания кастомного Toolbar в Compose. Основная задача — правильное центрирование заголовка и подзаголовка при динамическом контенте слева и справа (иконки, текст переменной длины).
Решения "в лоб" не сработали:
-
Row с Weight приводит к лишним рекомпозициям- Ручной расчет ширины текста — непредсказуемо и сложно
- Проблема в разных фазах измерения Compose
Решением стал кастомный Layout. Вместо стандартных компоновок используется
Layout, который измеряет все элементы за один проход.#Compose #Android #UI
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🤔3👎1
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥112👍8❤6👎1
Привет! Вышла стабильная версия Compose Multiplatform 1.10.0 с революционными изменениями для кроссплатформенной разработки. Давайте разберём главные фичи, которые изменят ваш подход к KMP.
🔥 Главная фишки релиз - Preview аннотация теперь работает в коде из commonMain — наконец-то!
// Работает в commonMain!
@Preview
@Composable
fun MyComponentPreview() {
MyTheme {
MyComponent()
}
}
МИГРАЦИЯ! Депрекейт
org.jetbrains.compose.ui.tooling.preview.Preview → переходите на androidx.compose.ui.tooling.preview.Preview👉 Compose Hot Reload встроен в Compose плагин и подключать отдельно больше не нужно
adaptive-navigation3⚠️ Breaking Changes & Миграция
Требования к версиям Kotlin
- Kotlin 2.1.20+ (обязательно из-за Hot Reload)
- Kotlin 2.2+ для native и web платформ
// build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation(compose.ui)
// Заменяем на
implementation("org.jetbrains.compose.ui:ui:1.10.0")
}
}
}
Кто уже обновился? Какие впечатления от Preview в commonMain? Делитесь в комментариях!
#compose #gradle #kmp #android #ios #desktop
Please open Telegram to view this post
VIEW IN TELEGRAM
❤37🔥27👍3👎2
Обновляйте зависимости или сразу всё через BOM файл:
dependencies {
implementation(
platform("androidx.compose:compose-bom-beta:2026.01.00")
)
}#compose #android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25👎2
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