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

Для чего нужен @Stable в Jetpack Compose?

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

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

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

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

Назначение аннотации @Stable в Jetpack Compose

@Stable — это аннотация-подсказка для компилятора Compose, которая сообщает системе, что определённый тип, функция или свойство являются "стабильными". Это ключевой механизм для оптимизации рекомпозиции и предотвращения избыточных перерисовок UI.

Основная цель: оптимизация системы рекомпозиции

Система smart recomposition в Compose старается перерисовывать только те части UI (Composable-функции), чьи входные параметры (inputs) изменились. Чтобы определить, изменились ли они, Compose использует проверку на равенство (equality).

  • Если все параметры функции стабильны и не изменились, Compose может пропустить её выполнение.
  • Если хотя бы один параметр нестабилен, Compose вынужден считать его изменённым при каждой рекомпозиции, что может приводить к избыточным перерисовкам.

@Stable даёт компилятору две гарантии о помеченной сущности:

  1. Результаты equals для двух экземпляров будут одинаковыми на протяжении всего их жизненного цикла.
  2. При изменении значения типа все его свойства, от которых зависит публичное состояние, будут обновлены одновременно (публикация изменений атомарна).

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

Практические сценарии использования

1. Стабилизация пользовательских типов данных (data-классов)

Без аннотации @Stable Compose не может быть уверен в неизменяемости и стабильности вашего класса, даже если это data class.

// Без @Stable: Compose будет считать этот тип нестабильным,
// что может приводить к избыточным рекомпозициям.
data class User(val name: String, val age: Int)

// С @Stable: даём компилятору явную гарантию стабильности.
@Stable
data class StableUser(val name: String, val age: Int)

@Composable
fun UserProfile(user: StableUser) {
    // Compose теперь уверен, что если `user` не изменился по `equals`,
    // то эту функцию можно безопасно пропустить.
    Text(text = "${user.name}, ${user.age}")
}

2. Стабилизация интерфейсов состояний (UI State)

Наиболее мощное применение — для взаимодействия с ViewModel и классами состояния в архитектуре MVVM или MVI.

// Без аннотации каждый вызов `uiState.value` может считаться изменением.
class MyViewModel : ViewModel() {
    private val _uiState = mutableStateOf(UiState())
    val uiState: State<UiState> = _uiState
}

// С аннотацией мы даём гарантию для всего типа UiState.
@Stable
data class UiState(
    val isLoading: Boolean = false,
    val data: List<Item> = emptyList(),
    val error: String? = null
)

class MyOptimizedViewModel : ViewModel() {
    private val _uiState = mutableStateOf(UiState())
    val uiState: State<UiState> = _uiState // Compose сможет лучше оптимизировать чтение
}

3. Функции как свойства (делегаты) в интерфейсах

Часто используется внутри Compose-кода для создания декларативных API.

@Stable
interface ToggleState {
    val isOn: Boolean
    fun onToggle()
}

@Composable
fun rememberToggleState(isInitiallyOn: Boolean = false): ToggleState {
    val (isOn, setOn) = remember { mutableStateOf(isInitiallyOn) }
    return remember(isOn) {
        // Благодаря @Stable на интерфейсе, эта лямбда станет стабильным типом.
        object : ToggleState {
            override val isOn: Boolean get() = isOn
            override fun onToggle() { setOn(!isOn) }
        }
    }
}

Важные нюансы и предупреждения

  • Это подсказка, а не проверка. Компилятор верит вам на слово. Если вы пометите изменяемый класс как @Stable и будете менять его поля без уведомления Compose (например, без MutableState), это приведёт к непредсказуемому поведению UI, так как Compose пропустит необходимые рекомпозиции.
  • Уже стабильные типы. Многие типы уже стабильны по умолчанию: все примитивы (Int, String, Float и т.д.), функциональные типы (лямбды) и классы, помеченные @Immutable. Аннотация @Immutable — более строгая разновидность @Stable, гарантирующая полную неизменяемость.
  • Когда не стоит использовать. Не применяйте аннотацию к по-настоящему изменяемым классам. Вместо этого для изменяемого состояния используйте mutableStateOf(), который сам предоставляет стабильный тип State<T>.

Итог

@Stable — это инструмент тонкой оптимизации производительности для опытных разработчиков. Его главная задача — дать компилятору Compose дополнительные гарантии о стабильности ваших пользовательских типов, что позволяет системе рекомпозиции чаще и безопаснее пропускать перерисовку функций, не влияя на корректность UI. Однако его применение требует чёткого понимания модели данных и ответственности за соблюдение данных гарантий.