Насколько стабилен интерфейс List в Jetpack Compose и как с этим работать?
Что проверяют
Знаете ли вы, что стабильность в Compose это термин компилятора, а не про то, что список не мигает. Компилятор помечает типы стабильными или нестабильными, и от этого зависит, сможет ли composable пропустить рекомпозицию. Вопрос отделяет тех, кто разбирался с выводом стабильности, от тех, кто оптимизирует списки наугад.
Как отвечать
kotlin.collections.List нестабилен, и это не баг: за интерфейсом может стоять mutableListOf, и компилятор не вправе обещать, что содержимое не изменится без смены ссылки. Из-за этого composable с параметром List<Item> не становится пропускаемым и перерисовывается вслед за родителем, даже когда данные те же.
Что с этим делают:
kotlinx.collections.immutableи параметр типаImmutableListилиPersistentList, они помечены стабильными;- обёртка:
data classс аннотацией@Immutable, внутри обычный список; - файл конфигурации стабильности, если нестабильный тип приезжает из чужой библиотеки и править его нельзя;
- сильный пропуск рекомпозиции, включённый по умолчанию в новых версиях плагина компилятора: нестабильные параметры сравниваются по ссылке, и функция всё равно становится пропускаемой.
Отдельно про сам список: в LazyColumn задавайте key по устойчивому идентификатору и contentType для разнородных ячеек. Это уже не про вывод стабильности, а про то, чтобы состояние и анимация не переехали на соседа при вставке в середину.
И назовите способ проверки: отчёты компилятора показывают по каждой функции, пропускаемая она или нет. Гадать не нужно.
Где спотыкаются
Считают, что val items: List<Item> неизменяемый, а значит стабильный. val запрещает переприсваивание ссылки и ничего не говорит про содержимое, а вывод компилятора смотрит на тип.
Второе: надеются, что сильный пропуск закрыл тему, и продолжают фильтровать или сортировать прямо в теле composable. Новый список это новая ссылка на каждом проходе, сравнение по ссылке тут не спасает: вычисление надо поднять в модель или завернуть в remember.
Третье: берут ключом сам элемент или его позицию. Повторяющиеся значения дают одинаковые ключи и падение в рантайме, а индекс при вставке в начало сдвигает состояние всех ячеек сразу.