TGViewer
Kotlin Kotlin @kotlin_lib · 2.05K subscribers
Post #694 789
📉 Ваш List убивает перформанс Compose. Разбираемся со Stability

Написали красивый экран на Compose. Данные не меняются, но Layout Inspector показывает, что ваш Composable со списком перерисовывается каждый чих. Почему?

Потому что вы передали туда обычный List.


@Composable
fun UsersList(users: List<User>) { // ❌ Компилятор вам не верит
// ...
}



В чем проблема?
Compose опирается на концепцию Stability (стабильности), чтобы понимать, можно ли «скипнуть» (пропустить) рекомпозицию узла, если параметры не изменились.
Но в Kotlin List это просто интерфейс (read-only). Под капотом туда легко может прилететь MutableList или ArrayList.
Compose не может гарантировать, что этот список кто-то не изменит из другого потока без ведома фреймворка. Поэтому компилятор помечает List как Unstable.
А если параметр Unstable - Compose всегда будет вызывать рекомпозицию этой функции, если перерисовался родитель.

Как это лечить? Есть три пути.

1. Официальный (и самый чистый): kotlinx.collections.immutable
Используем библиотеку от JetBrains. Там лежат настоящие неизменяемые коллекции.


@Composable
fun UsersList(users: ImmutableList<User>) { // ✅ Stable!
// ...
}



Компилятор Compose обучен доверять ImmutableList и PersistentList. Рекомпозиция будет скипаться.
Минус: Приходится маппить .toImmutableList() на слое ViewModel, что создает аллокации (хоть и оптимизированные).

2. Суровый (через врапперы)
Если вы не хотите тащить новую либу в проект, можно обернуть список в класс и зафорсить стабильность аннотацией:


@Immutable
@JvmInline
value class UsersState(val items: List<User>)

@Composable
fun UsersList(state: UsersState) { // ✅ Stable!
// ...
}



Мы берем ответственность на себя. Мы клянемся компилятору (через @Immutable), что не будем мутировать этот List под капотом.

3. Современный (Strong Skipping Mode)
Начиная с Compose Compiler 2.0, JetBrains включили Strong Skipping Mode по умолчанию.
Это меняет правила игры! Теперь Compose умеет скипать функции даже с Unstable параметрами (например, обычным List).
Как? Он просто сравнивает инстансы по ссылке (===). Если вы передали тот же самый объект списка, что и в прошлый раз - рекомпозиции не будет.
Но если ваша ViewModel при каждом обновлении делает uiState.copy(users = users.toList()) - инстанс меняется, и рекомпозиция всё равно ударит по UI.

Вывод: Strong Skipping Mode сильно спасает легаси-код от тормозов. Но архитектурно правильно - использовать ImmutableList. Это делает контракт вашей UI-модели железобетонным: "эти данные не мутируют".

А что в вашем проекте? Тащите kotlinx.collections.immutable, пишите врапперы или просто надеетесь на Strong Skipping? 👇

✍️ @kotlin_lib
  • 👍 4
More from @kotlin_lib
  1. Aug 26, 2026🚧 Ваш Mutex тормозит корутины. Как перестать лочить и начать жить Вы пишете многопоточный…
  2. Jul 25, 2026🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.r…
  3. Jul 1, 2026🌪 Ваша дата в опасности: flatMapConcat vs Merge vs Latest Вам нужно взять поток ID-шников…
  4. Jun 24, 2026🤖 Android-приложение — это не только красивый экран. За ним стоят работа с внешним API, з…
  5. Jun 23, 2026🔮 Убийца бойлерплейта: Встречайте Context Parameters (Kotlin 2.x) Мы так привыкли к Depen…
  6. Jun 3, 2026Яндекс обновил Yandex Mobile Ads SDK для монетизации мобильных приложений — и это интересн…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →