Фазы, skipping и ключи списка
Почему лишняя рекомпозиция и неверная идентичность — разные проблемы
Чтение состояния определяет работу
Compose различает composition, layout (измерение и размещение) и drawing. Чтение state в конкретной фазе позволяет инвалидировать нужную работу. Поэтому изменение цвета, читаемого в draw, не обязано заново строить композицию. Перенос чтения в layout-лямбду полезен лишь тогда, когда это соответствует свойству. Фазы Compose.
Стабильность — договор
В Compose Compiler для Kotlin 2.0.20 strong skipping включён по умолчанию. Restartable-функции могут пропускаться и с unstable-параметрами: для них сравнивается идентичность (===), для stable — равенство. Это не превращает скрытую мутацию обычного списка в наблюдаемое изменение. Ложный @Stable не лечит модель данных. Strong skipping.
Идентичность строки важнее её позиции
LazyColumn {
items(notes, key = { it.id }) { note ->
NoteRow(note)
}
}
notes здесь — список моделей с уникальным стабильным id; нужны импорты LazyColumn и items из androidx.compose.foundation.lazy. Если вставить элемент в начало списка с позиционными ключами, локальное состояние строк может сопоставиться не с теми данными. Для восстановления rememberSaveable в Android lazy-списке ключ должен поддерживаться Bundle, например String или Long. Ключи lazy-списков.
Измеряйте то, что мешает пользователю
Счётчик рекомпозиций сам по себе не является временем кадра. Проверяйте дорогие вычисления, работу layout/draw и состояние release-компиляции. derivedStateOf полезен, когда производное значение меняется реже исходного, а не для любой конкатенации строк. derivedStateOf.
Основа отбора: draft/compose_base.md, draft/faq500.md.