Что делать, если список с аннотацией stable в Jetpack Compose все равно тормозит?
Что проверяют
Понимаете ли вы, что стабильность влияет только на пропуск рекомпозиции, и знаете ли три фазы Compose. По ответу видно, меряли ли вы производительность вообще или повторяете советы из статей.
Как отвечать
Сразу уточните, где тормозит: долгий первый показ, рывки при прокрутке или подвисание при обновлении данных. Дальше по порядку.
Сначала условия замера. Отладочная сборка Compose медленнее релизной в разы: код идёт без оптимизаций, часть работы выполняется интерпретатором. Мерить нужно релизную сборку со сжатием кода и профилем запуска, иначе вы будете чинить несуществующую проблему.
Потом инструменты вместо догадок: счётчик рекомпозиций в инспекторе разметки, системная трасса, макробенчмарк по времени кадра. Он и покажет, что именно дорого: композиция, размещение или отрисовка.
Типичные находки в списке:
- у элементов нет устойчивого
key, и вставка в начало пересобирает всё ниже; - не задан
contentTypeу разнородных элементов, переиспользование не работает; - состояние прокрутки читается прямо в теле composable, поэтому каждый кадр вызывает композицию вместо одного лишь размещения. Помогают лямбда-версии модификаторов и
derivedStateOf; - сортировка, фильтрация или форматирование выполняются на каждый кадр вместо
remember; - внутри элемента лежит
BoxWithConstraintsили вложенная прокрутка, а это дорогое измерение.
Про аннотацию скажите прямо: @Stable это обещание компилятору, а не оптимизация. Если помеченный класс на деле меняется, вы получите не скорость, а устаревший кадр.
Где спотыкаются
Развешивают @Stable и @Immutable по классам с изменяемыми полями. Компилятор верит на слово, и вместо ускорения появляется список, который перестаёт обновляться.
Второе: сравнивают отладочные сборки. Разница с релизной такая, что любой вывод из подобного замера бессмыслен.
Третье: считают, что тормоз это всегда рекомпозиция. Кадр проседает и на отрисовке: тяжёлые тени, прозрачность, картинки без нужного размера, и никакая стабильность тут не поможет.