Какие способы оптимизации производительности есть в Jetpack Compose?
Что проверяют
Понимаете ли вы модель рекомпозиции: что Compose перезапускает не весь экран, а конкретные scope, и что мешает ему пропустить лишнее. Следом спрашивают, как вы это измеряли, поэтому хороший ответ обязан заканчиваться инструментом, а не догадкой.
Как отвечать
Стройте рассказ вокруг трёх фаз кадра: composition, layout, drawing. Общий принцип: чем позже читается изменяющееся состояние, тем дешевле обновление.
- стабильность типов: функция пропускается, если её параметры стабильны и не изменились. Сильный пропуск (strong skipping) включён по умолчанию в компиляторе начиная с Kotlin 2.0.20, поэтому нестабильный класс сам по себе больше не блокирует пропуск, но
@Immutable,@Stableиkotlinx.collections.immutableпо-прежнему помогают со списками; remember: не даёт пересчитывать дорогое между рекомпозициями. Ключи обязательны, иначе значение устареет;derivedStateOf: когда из часто меняющегося состояния выводится редко меняющееся, классика этоfirstVisibleItemIndex > 0для показа кнопки «наверх»;- отложенное чтение:
Modifier.offset { }иgraphicsLayer { }с лямбдой читают состояние в фазе layout или draw, поэтому анимация не тянет за собой рекомпозицию. По той же причине вниз передают лямбду, а не готовое значение; - списки:
LazyColumnсitems(list, key = { it.id })иcontentType, чтобы переиспользовались правильные слоты; - подъём состояния: держите
MutableStateкак можно ближе к месту использования, тогда перезапустится маленький scope, а не весь экран.
Замеры: отчёты компилятора Compose про стабильность параметров, счётчик рекомпозиций в Layout Inspector, Macrobenchmark и baseline profiles для запуска и скролла, JankStats на проде.
Где спотыкаются
Судят о плавности по debug-сборке. Мерить нужно release с R8, иначе выводы про производительность ложные.
Оборачивают всё подряд в remember и derivedStateOf. У обоих есть цена, а derivedStateOf без реального сужения обновлений просто добавляет слой.
Читают состояние анимации на верхнем уровне экрана и передают вниз число. Каждый кадр перезапускает всю композицию, хотя двигается один элемент.