Императивный и декларативный UI
Этот урок объясняет, чем декларативный UI отличается от старого императивного и почему Compose меняет правила игры.
Декларативный UI — это подход, при котором вы описываете, как интерфейс должен выглядеть для текущего состояния, а фреймворк сам решает, что и когда перерисовать.
Как было раньше: императивный View
Долгие годы Android-разработчики верстали экраны в XML, а потом «оживляли» их в коде. Чтобы поменять текст, нужно было найти виджет по идентификатору и вручную выставить ему новое значение:
val textView = findViewById<TextView>(R.id.title)
textView.text = "Привет"
val button = findViewById<Button>(R.id.btn)
button.setOnClickListener {
textView.text = "Нажато!"
}Это императивный стиль: вы отдаёте пошаговые команды («найди виджет», «поставь текст», «повесь обработчик»). Проблема в том, что состояние живёт в двух местах — в ваших переменных и внутри самих виджетов. Их легко рассинхронизировать: забыли обновить один TextView — и на экране устаревшие данные.
Как стало: декларативный Compose
В Compose вы не дёргаете виджеты. Вы пишете функцию, которая по входным данным возвращает описание интерфейса. Поменялись данные — функция вызывается заново и рисует новую картинку:
@Composable
fun Greeting(name: String) {
Text(text = "Привет, $name")
}Здесь нет findViewById, нет ручного setText. Есть единственный источник истины — параметр name. Изменился он — Compose сам перерисует Text. Вам не нужно следить за синхронизацией.
Аналогия
Императивный подход — это инструкция роботу-маляру: «возьми кисть, обмакни в синюю краску, проведи слева направо». Декларативный — это фраза «стена должна быть синей». Как именно её покрасить, фреймворк решает сам.
Как работает под капотом
Compose-функции не возвращают объекты View. При вызове они регистрируют в специальном дереве описание того, что нужно нарисовать. Это дерево называют композицией. Когда данные меняются, Compose сравнивает новое описание со старым и обновляет только те узлы, которые реально изменились. Этот процесс называется recomposition — мы подробно разберём его в третьем разделе.
Важно: вызов Greeting("Аня") не значит «нарисуй прямо сейчас». Это значит «опиши, что для имени Аня экран выглядит так». Когда и сколько раз функция выполнится — забота фреймворка.
Частые ошибки
- Пытаться «достучаться» до виджета и поменять его вручную, как в старой системе. В Compose так нельзя — меняйте состояние, а не UI.
- Думать, что composable-функция выполняется один раз. Она может вызываться много раз при каждом изменении данных.
- Складывать логику с побочными эффектами (запись в файл, сетевой запрос) прямо в тело composable — она будет срабатывать на каждой перерисовке.
Итог
- Императивный UI: вы вручную меняете виджеты, состояние дублируется и рассинхронизируется.
- Декларативный UI: вы описываете картинку по данным, фреймворк сам обновляет экран.
- В Compose единственный источник истины — состояние, а не сами виджеты.