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

Как избежать большого количества рекомпозиций?

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

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

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

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

Оптимизация рекомпозиций в Jetpack Compose: стратегии и лучшие практики

Основная цель оптимизации — минимизировать количество вызовов recompose scope, особенно для дорогих в вычислениях UI-элементов. Вот ключевые стратегии:

1. Правильное использование ключевых модификаторов и функций

Стабильные классы данных — помечайте data классы как @Stable или используйте @Immutable для коллекций, чтобы Compose мог лучше отслеживать изменения:

@Immutable
data class UserState(val name: String, val score: Int)

Ключи для Lazy-списков — всегда предоставляйте стабильные ключи:

LazyColumn {
    items(
        items = users,
        key = { it.id } // Уникальный стабильный идентификатор
    ) { user ->
        UserItem(user)
    }
}

2. Контроль области рекомпозиции

Дробление на мелкие composable-функции — Compose рекомпозирует только измененные функции:

// ПЛОХО: весь блок будет рекомпозирован при изменении count
@Composable
fun BadCounter() {
    Column {
        Text("Заголовок") // Рекомпозируется зря
        Text("Счет: $count")
    }
}

// ХОРОШО: только нужная часть
@Composable
fun GoodCounter() {
    Column {
        Header() // Стабильный элемент
        CounterText(count) // Рекомпозируется только при изменении count
    }
}

@Composable
fun CounterText(count: Int) {
    Text("Счет: $count")
}

3. Оптимизация с помощью производных состояний

remember и derivedStateOf — предотвращают рекомпозиции при незначительных изменениях:

@Composable
fun ExpensiveList(items: List<Item>) {
    val visibleItems = remember(items) {
        derivedStateOf {
            items.filter { it.isVisible }
        }
    }
    // Рекомпозиция только при реальном изменении visibleItems
    LazyColumn {
        items(visibleItems.value) { item ->
            ItemRow(item)
        }
    }
}

4. Использование side effects с умом

LaunchedEffect и DisposableEffect — выносите логику, не связанную с UI:

@Composable
fun TimerDisplay() {
    var time by remember { mutableStateOf(0) }
    
    LaunchedEffect(Unit) { // Запускается один раз
        while (true) {
            delay(1000)
            time++ // Изменение состояния вызывает рекомпозицию только Text
        }
    }
    
    Text("Прошло секунд: $time") // Рекомпозируется только этот элемент
}

5. Оптимизация работы с состояниями

Локальное состояние vs ViewModel — храните UI-состояние локально, если оно не нужно бизнес-логике:

@Composable
fun ToggleButton() {
    var isChecked by remember { mutableStateOf(false) } // Локальное состояние
    
    Switch(
        checked = isChecked,
        onCheckedChange = { isChecked = it } // Рекомпозируется только Switch
    )
}

State hoisting — поднимайте состояние к месту, где оно реально используется:

@Composable
fun ParentComponent() {
    var textState by remember { mutableStateOf("") }
    
    // Дочерние компоненты получают только необходимые параметры
    ChildInput(text = textState, onTextChange = { textState = it })
}

@Composable
fun ChildInput(text: String, onTextChange: (String) -> Unit) {
    TextField(value = text, onValueChange = onTextChange)
}

6. Инструменты отладки и анализа

Включите в build.gradle:

composeOptions {
    kotlinCompilerExtensionVersion = "1.5.4"
}

Используйте модификатор debugInspectorInfo или Layout Inspector в Android Studio для визуализации рекомпозиций.

7. Дополнительные техники

  • remember с вычислениями — кэшируйте тяжелые вычисления
  • Пропускайте параметры по умолчанию — Compose пропускает рекомпозицию, если все параметры имеют стабильные значения и не изменились
  • Используйте @ReadOnlyComposable для функций, которые только читают данные

Ключевой принцип: рекомпозиция — это не всегда плохо. Jetpack Compose оптимизирован для быстрых рекомпозиций. Проблемой становится только избыточная рекомпозиция дорогих вычислений. Измеряйте производительность с помощью Benchmark и JankStats, прежде чем оптимизировать. Часто достаточно разделить крупные composable-функции на более мелкие, чтобы добиться значительного улучшения производительности.