Compose Broadcast
5.89K subscribers
353 photos
90 videos
577 links
Все о Jetpack Compose и Compose Multiplatform

YouTubе канал: https://youtube.com/androidBroadcast
Android - @android_broadcast
iOS - @ios_broadcast
Kotlin - @kotlin_broadcast
Download Telegram
📺 Короткое видео (EN,4м) от команды Android про адаптация Edge-to-Edge (отображения UI приложения под системными панелями) когда ваш UI на Compose. Почитать можно тут

#android #edgetoedge
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15
⚙️ Pausable composition in lazy prefetch: как Compose теперь борется с лагами при прокрутке

Важное изменение в Compose 1.10: pausable composition в lazy prefetch теперь включен по умолчанию. Это фундаментальное улучшение в работе runtime, которое значительно уменьшает лаги при сложных UI-нагрузках.

Раньше композиция, раз начавшись, должна была выполниться до конца. Если она была сложной (много элементов, тяжелые вычисления), это могло заблокировать главный поток дольше, чем длится один кадр и получали Freeze Frame и визуальные лаги скролла.

Теперь Compose Runtime может приостанавливать работу, если время на отрисовку кадра заканчивается, и продолжить её в следующем интервале. Особенно эффективно это работает в связке с предзагрузкой (prefetch) ленивых списков.

🔄 Как это работает с Lazy layouts:

// Увеличиваем окно кэша для большего пространства предзагрузки
val cacheWindow = LazyLayoutCacheWindow(
ahead = 0.5f, // 50% вперед
behind = 0.3f // 30% назад
)

val state = rememberLazyListState(cacheWindow = cacheWindow)

LazyColumn(state = state) {
items(heavyItems) { item ->
HeavyComposable(item) // Теперь не заблокирует UI
}
}


🎯 Ключевые преимущества:
1. Плавная прокрутка — даже с тяжелыми элементами
2. Композиция подстраивается под время для отрисовки кадра — композиция «уступает» место другим операциям
3. Никакой сложной настройки — не требует изменения кода приложения

Эта оптимизация — часть продолжающейся работы Google над производительностью Compose. Уже пробовали? Делитесь наблюдениями в комментариях!

#Compose #Производительность #AndroidDev #JetpackCompose
Please open Telegram to view this post
VIEW IN TELEGRAM
👍46🔥177
⚙️ Dejavu — тесты на рекомпозицию в Compose

Мэтт МакКенна выпустил библиотеку, которая превращает рекомпозиции в обычные 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 тест.

🐱 Dejavu Github

#Android #AndroidDev #Compose #JetpackCompose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥46👏75👎4🤔2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
⚙️ Анимации в Jetpack Compose LazyColumn: почему это сложнее, чем кажется

Наткнулся на отличный разбор от ребят из Т-Банка — они переписывали главный экран с 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👎138👍2