Что такое жизненный цикл в Jetpack Compose и как происходит позиционный менеджмент и отрисовка
Что проверяют
Понимаете ли вы, что у composable нет onCreate и onDestroy, что его жизнь описывается тремя событиями в композиции, и как Compose вообще понимает, какой вызов какому узлу соответствует. Вопрос отделяет тех, кто перенёс мышление View в Compose, от тех, кто принял новую модель.
Как отвечать
Жизненный цикл composable: вход в композицию, ноль или больше рекомпозиций, выход из композиции. Колбэков нет, побочные эффекты привязывают к этим событиям через LaunchedEffect и DisposableEffect с его onDispose, значение между рекомпозициями хранит remember, а пережить смену конфигурации и смерть процесса помогает rememberSaveable.
Позиционный менеджмент это позиционная мемоизация. Compose различает вызовы не по имени функции, а по месту вызова в исходном коде, плагин компилятора расставляет ключи групп. Поэтому два одинаковых вызова подряд это два разных узла со своим состоянием, а в цикле по списку нужен key, иначе при вставке или удалении элемента состояние переедет к соседу.
Кадр проходит три фазы: композиция решает, что рисовать, размещение измеряет и расставляет (узел получает ограничения и возвращает размер, дети измеряются за один проход), отрисовка рисует. Чтение состояния внутри лямбды поздней фазы ограничивает обновление этой фазой: смещение через лямбду или graphicsLayer двигает элемент без композиции.
Где спотыкаются
Ждут аналог onDestroy и освобождают ресурсы в теле composable. Тело выполняется часто, в произвольном порядке и потенциально параллельно, поэтому побочные эффекты там запрещены, а освобождение живёт в onDispose.
Считают, что изменение состояния перерисовывает экран целиком. Перекомпонуется ближайшая область, которая читает это состояние, и типовая беда обратная: состояние читают слишком высоко по дереву и перекомпоновывают половину экрана вместо того, чтобы передать вниз лямбду.
Не ставят ключи в ленивых списках и считают позиционную мемоизацию деталью вёрстки. Сюда же относится remember без ключей, который продолжает отдавать значение, посчитанное для прежних входных данных.