Recomposition: когда и что перерисовывается
Разбираемся в главном механизме Compose — recomposition — и понимаем, что и когда перерисовывается.
Recomposition — повторный вызов composable-функций при изменении состояния, чтобы обновить интерфейс в соответствии с новыми данными.
Что запускает recomposition
Перерисовка случается только тогда, когда меняется наблюдаемое состояние (созданное через mutableStateOf), которое читается внутри composable. Compose умный: он перевыполняет не всё дерево, а лишь те функции, что зависят от изменившегося значения.
@Composable
fun Profile() {
var likes by remember { mutableStateOf(0) }
Column {
Text(text = "Профиль пользователя") // читает только статичный текст
LikeButton(likes) { likes++ } // зависит от likes
}
}Когда likes растёт, Compose перерисует LikeButton (он читает likes), но заголовок «Профиль пользователя» трогать не будет — он от likes не зависит. Это и есть ключевое отличие от перерисовки экрана целиком: Compose отслеживает чтения состояния на уровне отдельных функций и обновляет только затронутые ветки дерева. Поэтому даже на сложном экране изменение одного счётчика обычно стоит копейки.
Composable могут выполняться в любом порядке
Compose не гарантирует порядок и количество вызовов. Одна и та же функция может выполниться много раз, может — параллельно, может — пропуститься, если её входные данные не изменились. Поэтому composable должны быть идемпотентными: при тех же входных данных давать тот же результат, без неожиданных эффектов.
Что значит «без эффектов»
Нельзя в теле composable увеличивать внешний счётчик, писать в лог при каждом проходе или слать запрос в сеть. Эти действия повторятся непредсказуемое число раз. Для побочных эффектов есть отдельные инструменты — о них в шестом разделе.
Как работает под капотом
Compose ведёт «слоты» — память, где хранятся результаты прошлой композиции. При recomposition он сравнивает новые параметры со старыми. Если параметры composable не изменились и функция помечена как пропускаемая (skippable), Compose пропускает её вызов и переиспользует прошлый результат. Так достигается эффективность: перерисовывается лишь то, что реально поменялось.
Частые ошибки
- Класть в тело composable побочные эффекты (логи, запросы) — они срабатывают на каждой перерисовке.
- Рассчитывать на конкретный порядок выполнения composable — его нет.
- Думать, что recomposition перерисовывает весь экран целиком — обычно это узкая область.
Итог
- Recomposition запускается при изменении читаемого composable наблюдаемого состояния.
- Перерисовываются только зависящие функции, остальное пропускается.
- Composable должны быть чистыми: без побочных эффектов в теле.