Что такое SnapshotStateList в Jetpack Compose
Что проверяют
Понимаете ли вы систему снапшотов, на которой держится Compose: как именно изменение данных приводит к перерисовке и почему обычный mutableListOf так не умеет.
Как отвечать
SnapshotStateList это реализация MutableList, встроенная в систему состояний Compose. Создаётся через mutableStateListOf() или toMutableStateList(). Чтение списка внутри композиции регистрируется как чтение состояния, запись помечает эту область устаревшей, и рекомпозиция происходит сама.
Ключевое отличие от mutableStateOf(listOf()): там наблюдаемо только присваивание новой ссылки, и ради обновления интерфейса список пересоздают целиком. Здесь наблюдаемы сами операции, то есть добавление, удаление и замена по индексу.
val tasks = remember { mutableStateListOf<Task>() }
tasks += Task(title = "Написать тест")Что добавить сверх определения:
- переживает смерть процесса и поворот только если лежит во
ViewModelили обёрнут вrememberSaveableс подходящим сохранятором; - запись из фонового потока делают внутри снапшота, иначе изменения теряются между кадрами;
- тип считается стабильным, поэтому его передача параметром не ломает пропуск рекомпозиции;
- длинные списки читают через
LazyColumnс ключами, иначе перерисовка задевает все элементы.
Где спотыкаются
Оборачивают обычный список в состояние и мутируют его внутренность: сначала mutableStateOf(mutableListOf()), потом добавление элемента. Ссылка прежняя, снапшот ничего не заметил, интерфейс не обновился. Это самая частая жалоба на то, что Compose якобы не реагирует.
Меняют поле у элемента и ждут перерисовку. Список наблюдает за своим содержимым, а не за внутренностями объектов в нём. Либо элемент делают неизменяемым и заменяют копией, либо его поля тоже кладут в состояние.
Поднимают такой список во ViewModel и раздают наружу как общий изменяемый объект. Писать в него начинают из нескольких мест, порядок операций становится непредсказуемым. Наружу отдают неизменяемый тип, а правки проводят методами модели.