← Назад к вопросам

Как работает recomposition в Jetpack Compose? Что такое remember и rememberSaveable?

1.8 Middle🔥 191 комментариев
#UI и вёрстка#Производительность и оптимизация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизм Recomposition в Jetpack Compose

Recomposition — это ключевой процесс в Jetpack Compose, который позволяет системе автоматически и эффективно обновлять UI при изменении состояния. Понимание recomposition критически важно для написания производительных и корректных Compose-приложений.

Основные принципы работы

Recomposition — это повторный вызов composable-функций (или их частей) при изменении входных данных (State). Композиция (Composition) — это первоначальное построение дерева UI путем вызова всех composable-функций. При изменении любого наблюдаемого состояния (например, через State или MutableState), Compose запускает recomposition для тех узлов дерева, которые зависят от этого измененного состояния.

  1. Интеллектуальное и инкрементальное обновление: Compose не перестраивает весь UI дерево целиком. Он использует "снимок" предыдущей композиции и сравнивает входные параметры (state) каждой composable-функции. Если параметры изменились, функция вызывается повторно (рекомпозируется). Если параметры остались прежними, Compose может полностью пропустить вызов этой функции и всех её потомков в дереве UI.
  2. Нестабильные входные параметры и Skippability: Чтобы оптимизация "пропуска" работала, параметры функции должны быть стабильными. Стабильный тип — это тип, у которого equals работает корректно, и его экземпляры не меняются после создания (например, все примитивы, String, и все State типы). Если функция принимает нестабильный класс как параметр (например, обычный класс данных), она не сможет быть пропущена при recomposition, что может привести к потере производительности.
  3. Позиционная мемоизация (Positional Memoization): Compose "помнит" результаты вызова функций для каждой позиции в дереве. При recomposition он знает, какие функции были вызваны в какой последовательности, и может сравнивать их входные данные именно для этих позиций.

Пример базового recomposition:

@Composable
fun CounterDisplay(count: Int) {
    Text(text = "Count: $count") // Эта Text будет рекомпозироваться только когда `count` меняется.
}

@Composable
fun MyScreen() {
    var countState by remember { mutableStateOf(0) }
    Column {
        CounterDisplay(countState) // Передает State как параметр.
        Button(onClick = { countState++ }) { // Изменение состояния запускает recomposition для CounterDisplay.
            Text("Increment")
        }
    }
}

Remember и RememberSaveable: сохранение состояния в композиции

Это ключевые инструменты для управления локальным состоянием composable-функции во время recomposition и конфигурационных изменений (например, поворот экрана).

Remember

remember — это функция, которая хранит результат вычисления во время жизни текущей композиции. Если composable-функция рекомпозируется, remember возвращает сохраненное значение, вместо повторного выполнения вычисления.

  • Задача: Предотвращать повторные дорогостоящие вычисления или воссоздание объектов при каждом вызове функции (рекомпозиции).
  • Срок жизни: Значение хранится до тех пор, пока composable-функция остается в композиции (т.е. пока она активна на экране). Если функция удаляется из дерева композиции (например, при навигации), значение теряется.
  • Использование: Чаще всего используется вместе с mutableStateOf для создания локального State, который вызывает recomposition при изменении.
@Composable
fun ExpensiveComposable() {
    // Значение будет вычислено только при первой композиции.
    // При всех последующих recomposition будет возвращено сохраненное значение.
    val expensiveResult = remember {
        performVeryHeavyCalculation()
    }
    Text(text = "Result: $expensiveResult")
}

Ключевое использование для состояния:

@Composable
fun MyToggle() {
    // Состояние `isChecked` сохраняется между recomposition.
    // При изменении `isChecked` вызывает recomposition этой функции.
    var isChecked by remember { mutableStateOf(false) }
    Checkbox(
        checked = isChecked,
        onCheckedChange = { newValue -> isChecked = newValue }
    )
}

RememberSaveable

rememberSaveable — это расширенная версия remember, которая добавляет возможность сохранять состояние через конфигурационные изменения системы (например, поворот экрана, изменение размера окна, процесс death).

  • Задача: Сохранять не только между recomposition, но и между полными пересозданиями Activity/Fragment (композиции).
  • Механизм: По умолчанию использует механизм Bundle Android (аналогично сохранению состояния в Activity.onSaveInstanceState()). Это означает, что тип данных должен поддерживать сохранение в Bundle (примитивы, String, Parcelable, Serializable и т.д.).
  • Для сложных объектов: Можно предоставить собственный Saver через параметр saver, чтобы определить, как объект сохраняется и восстанавливается.
@Composable
fun UserInputField() {
    // Текст в поле будет сохранен даже после поворота экрана.
    var userText by rememberSaveable { mutableStateOf("") }
    OutlinedTextField(
        value = userText,
        onValueChange = { newText -> userText = newText },
        label = { Text("Enter text") }
    )
}

Разница в поведении:

  • remember: Состояние теряется при конфигурационном изменении или когда composable удаляется из композиции.
  • rememberSaveable: Состояние сохраняется при конфигурационных изменениях, но также теряется, когда composable окончательно удаляется из композиции (например, при навигации на другой экран).

Вывод

Для эффективной работы с Jetpack Compose необходимо:

  1. Писать composable-функции так, чтобы они могли быть пропущены при recomposition (использовать стабильные параметры).
  2. Использовать remember для хранения локального состояния или результатов тяжелых вычислений во время текущей композиции.
  3. Использовать rememberSaveable для того же, но с дополнительным требованием сохранять состояние при конфигурационных изменениях системы.
  4. Всегда помнить, что изменение объекта, хранящегося в remember или rememberSaveable (особенно State), является триггером recomposition для тех composable, которые его читают.
Как работает recomposition в Jetpack Compose? Что такое remember и rememberSaveable? | PrepBro