Что такое аннотации @Stable и @Mutable в Jetpack Compose и когда их применяют
Что проверяют
Понимаете ли вы, как Compose решает, можно ли пропустить рекомпозицию, и что такое стабильность типа. Заодно проверяют внимательность: аннотации @Mutable в Compose нет, есть пара @Stable и @Immutable, и хороший ответ начинается с этой поправки. Следом спрашивают про strong skipping и про поиск нестабильных параметров.
Как отвечать
При рекомпозиции Compose может пропустить вызов composable-функции, если её параметры не изменились. Для этого компилятор определяет стабильность типов: примитивы, String, функциональные типы и классы только с val стабильных типов стабильны. Нестабильны классы с var, интерфейсы коллекций вроде List<T> (под ним может лежать изменяемый список) и классы из модулей, собранных без компилятора Compose.
@Immutable: обещание, что после создания ни одно публичное свойство не изменится. Подходит моделям данных только сvalи неизменяемыми полями;@Stable: мягче. Объект может меняться, ноequalsдля одних и тех же экземпляров даёт один и тот же результат, а изменение публичного свойства идёт через snapshot-состояние (mutableStateOf), так что Compose о нём узнает. Так помечают, например, держатели состояния экрана.
Обе аннотации это контракт, который компилятор не проверяет, он верит на слово.
Важная деталь: начиная с Kotlin 2.0.20 режим strong skipping включён по умолчанию. Функции с нестабильными параметрами тоже пропускаются, только такие параметры сравниваются по ссылке (===), а стабильные через equals. Поэтому аннотации нужны реже, чем в старых статьях. Разобраться помогают отчёты компилятора через reportsDestination в блоке composeCompiler, а чужие классы объявляют стабильными в файле конфигурации стабильности, не трогая их код.
Где спотыкаются
Рассказывают про @Mutable так, будто она существует. Это сразу видно и сильно портит впечатление.
Вешают @Immutable на класс с var или MutableList. Compose пропустит рекомпозицию, и экран перестанет обновляться после изменения данных.
Думают, что @Stable сама заставляет интерфейс обновляться. Изменения отслеживает State, а аннотация лишь разрешает Compose доверять equals и пропускать вызовы.