
Пять ошибок при работе с Jetpack Compose, из-за которых тормозит recomposition
badcasedaily1 25 минут назад Пять ошибок при работе с Jetpack Compose, из-за которых тормозит recomposition Средний 7 мин 928 Блог компании OTUS Jetpack Compose * Программирование * Android * Kotlin * Туториал Привет,...
Anthropic — What company has the best second artificial intelligence model at the end of June?
Вот важная новость с фронта ИИ: badcasedaily1 25 минут назад Пять ошибок при работе с Jetpack Compose, из-за которых тормозит recomposition Средний 7 мин 928 Блог компании OTUS Jetpack Compose * Программирование * Android * Kotlin * Туториал Привет, Хабр! Jetpack Compose в 2026 году стал стандартом разработки UI на Android, но в проектах регулярно повторяется одна и та же история: на экране со списком в пару сотен элементов прокрутка идёт рывками, профайлер показывает скачки кадров до 200 миллисекунд, а команда чешет голову и предлагает откатиться обратно на RecyclerView. Проблема почти всегда не в Compose, а в том, как написан UI: recomposition спроектирован как дешёвая операция, но эта дешевизна работает только при соблюдении ряда правил, которые в документации описаны рассыпанно и часто игнорируются.
Разберём пять ошибок, из-за которых производительность Compose-экранов проседает заметно для глаза, и покажем, как их находить и чинить. Лямбды без remember пересоздаются на каждой рекомпозицииЧасто встречающийся код, который выглядит логично:@Composable fun UserList(users: List, onUserClick: (User) -> Unit) { LazyColumn { items(users) { user -> UserCard( user = user, onUserClick(user) } ) } } } В каждой рекомпозиции UserList лямбда { onUserClick(user) } создаётся заново, и Compose видит её как новый объект. Если UserCard принимает onClick: () -> Unit без remember, Compose считает, что параметры изменились, и рекомпозит карточку, даже когда сам user остался прежним.
Технические детали
Решение, которое разработчики применяют чаще всего, выглядит так:items(users, key = { it. id }) { user -> val { { onUserClick(user) } } UserCard(user = user, }remember(user) кэширует лямбду, пересоздавая её только при смене пользователя. Это работает, но загромождает код.
Более чистая альтернатива: внутри UserCard принимать не () -> Unit, а (User) -> Unit и сам объект пользователя, тогда лямбда верхнего уровня стабильна сама по себе и не требует remember. Compose Compiler с включёнными compiler reports подсвечивает такие места: в выводе появляются строки про unstable parameters, и можно сразу видеть, где Compose не может пропустить recomposition. Включается флагом в build.
gradle, и через десять минут анализа из отчёта вытаскивается список проблемных точек. Нестабильные типы заставляют Compose не доверять параметрамCompose делит типы на stable и unstable. Stable типы (Int, String, enum, data class с immutable полями стабильных типов) Compose сравнивает по equals и пропускает рекомпозицию, если параметр не изменился.
Unstable типы (List, Map, Set, обычные классы с var-полями) Compose не считает безопасными для пропуска: даже если содержимое не менялось, рекомпозиция случится. Пример:data class ProductFilters( val categories: List, val priceRange: IntRange, val brands: List ) @Composable fun FilterPanel(filters: ProductFilters) { // Этот composable будет рекомпозиться при любой рекомпозиции родителя }List это интерфейс, под которым может скрываться mutable-реализация.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





