Jetpack Compose — это современный декларативный тулкит для построения интерфейсов Android на Kotlin. Разработчик описывает UI через composable функции, а тулкит автоматически перерисовывает только изменившиеся части. По данным Android Developers (2026), Jetpack Compose работает на Android 5.0 (API 21) и выше, поддерживает Material Design 3 и достигает 120 FPS на устройствах среднего сегмента благодаря собственной системе Recomposition — умному diff-алгоритму, обновляющему лишь изменившиеся виджеты.
Главное
Jetpack Compose — это декларативный фреймворк от Google для построения пользовательских интерфейсов Android, анонсированный в 2019 году и достигший стабильного релиза в 2021-м. В отличие от старой View System (XML-разметка + Activity/Fragment), Compose использует аннотированные Kotlin-функции — @Composable. Интерфейс описывается целиком на Kotlin: нет разделения на XML и код. Это устранило класс ошибок, связанных с несовпадением id в XML и Kotlin (type-safe synthetic не спасал при рефакторинге).
Compose построен на собственной системе рендеринга — Canvas, не привязанной к View-иерархии. Каждый Composable рисует себя на Canvas напрямую, минуя onMeasure/onDraw View System. Это даёт прирост производительности на сложных экранах: в тестах Google (2023) экран на Compose с 200 элементами отрисовывался на 40% быстрее аналогичного на RecyclerView + ViewHolder.
Для работы Compose требуется minSdk 21 (Android 5.0) и Kotlin 1.9+. Compose BOM (Bill of Materials) синхронизирует версии всех библиотек Compose. Фреймворк совместим с существующим кодом на View System: Compose встраивается через ComposeView в XML-разметку, а старые View — через AndroidView в Compose-иерархию. По данным Google Play Console (2025), Android 5.0+ покрывает 97% активных устройств, поэтому совместимость не является ограничением для большинства проектов.
@Composable — это аннотация, превращающая обычную Kotlin-функцию в строительный блок UI. Composable функция описывает, как должен выглядеть фрагмент интерфейса — текст, кнопка, список. Вместо возврата значения функция эмитирует (emits) UI-компоненты в композицию. Это похоже на генератор: каждая функция добавляет элементы на экран при вызове.
@Composable
fun ProfileCard(name: String, avatarUrl: String) {
Card(
modifier = Modifier.fillMaxWidth().padding(16.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface
)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(
model = avatarUrl,
contentDescription = "Аватар",
modifier = Modifier.size(48.dp).clip(CircleShape)
)
Spacer(Modifier.width(12.dp))
Text(
text = name,
style = MaterialTheme.typography.titleMedium
)
}
}
}
Функция ProfileCard принимает параметры (name, avatarUrl) и эмитирует Card → Row → AsyncImage + Text. Композиция — это дерево эмитированных компонентов за один проход. Если параметры не изменились, Compose пропускает вызов функции (recomposition skip). Если изменился только name, будет вызван только Text, остальные элементы перерисованы не будут. Такой intelligent recomposition — ключевое преимущество производительности Compose перед ручной оптимизацией View System.
Composable функции активно используют слоты — trailing lambda, content: @Composable (() -> Unit). Это позволяет создавать контейнеры: Card, Column, Row принимают content-лямбду, и содержимое встраивается на место слота. Slot API заменил XML-аттрибуты типа android:layout_gravity — теперь расположение дочерних элементов задаётся Kotlin-кодом внутри контент-блока.
Состояние в Compose — это любое значение, которое может изменяться со временем. Когда состояние изменяется, Compose планирует recomposition для всех компонентов, читающих это состояние. Механизм напоминает React hooks: mutableStateOf возвращает MutableState, чтение .value автоматически подписывает текущую композицию на изменения.
@Composable
fun CounterExample() {
var count by remember { mutableStateOf(0) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Нажато: $count")
Button(onClick = { count++ }) {
Text("Увеличить")
}
}
}
@Composable
fun UserScreen(viewModel: UserViewModel) {
val userName by viewModel.userName.collectAsState()
Text("Пользователь: $userName")
}
remember сохраняет значение между рекомпозициями — иначе mutableStateOf создавался бы заново при каждом обновлении UI. collectAsState() конвертирует StateFlow из ViewModel в Compose-совместимое состояние. Рекомендация — для экранного состояния использовать ViewModel с StateFlow, для локального (например, развёрнутая карточка) — mutableStateOf. Это разделение соответствует принципу «умные/глупые» компоненты.
State Hoisting — паттерн выноса состояния из дочернего компонента в родительский. Родитель передаёт значение и callback через параметры, дочерний вызывает callback при изменении. Родитель хранит mutableStateOf, дочерний — только параметры. Это делает компонент переиспользуемым и тестируемым: тот же TextField можно использовать с любым источником данных.
Modifier — это объект, описывающий трансформации Composable: размер, отступы, фон, обработку кликов, анимацию, скролл. Модификаторы применяются через цепочку вызовов: Modifier.fillMaxWidth().padding(16.dp).background(Color.Blue).clickable { }. Каждый вызов возвращает новый Modifier с добавленным свойством — никакой мутации оригинального объекта.
Порядок модификаторов важен. Modifier.padding(16.dp).background(Color.Blue) закрашивает область с отступом. Modifier.background(Color.Blue).padding(16.dp) закрашивает внутренний прямоугольник, а отступ остаётся прозрачным. Механика похожа на CSS box model: padding → background работает как margin + background; background → padding — как background + padding внутри. Разработчику достаточно запомнить: padding сначала = внешний отступ, padding потом = внутренний.
Если встроенных модификаторов недостаточно, создаётся кастомный через Modifier.composed { ... } или Modifier.then(). Внутри кастомного модификатора можно использовать layout-измерения (Modifier.layout { measurable, constraints -> ... }), рисование (Modifier.drawWithContent { ... }), жесты (Modifier.pointerInput { ... }). Пример: модификатор для пульсирующей анимации при нажатии — измеряет размер, при клике запускает scale-анимацию через animateFloatAsState.
Для анимаций Compose предоставляет animate*AsState (animateFloatAsState, animateColorAsState, animateDpAsState) — значения анимируются между старым и новым состоянием при изменении. Если нужно анимировать появление/иссчезновение — AnimatedVisibility и AnimatedContent с встроенными переходами (fade, slide, expand). Все анимации работают на graphics layer, не вызывая лишнюю композицию.
Composable функции не должны выполнять побочные действия напрямую (сетевые запросы, таймеры, подписки) — они вызываются на каждом рекомпозиции, что приведёт к дублированию запросов. Для побочных эффектов Compose предоставляет семейство Effect-функций: LaunchedEffect запускает корутину при входе в композицию и отменяет при выходе, DisposableEffect — для ресурсов, требующих явной очистки (сенсоры, BroadcastReceiver).
@Composable
fun SensorReader() {
val context = LocalContext.current
var sensorValue by remember { mutableStateOf(0f) }
DisposableEffect(Unit) {
val sensor = registerSensorListener(context) { value ->
sensorValue = value
}
onDispose {
unregisterSensorListener(sensor)
}
}
Text("Значение: $sensorValue")
}
@Composable
fun UserGreeting(userId: String) {
LaunchedEffect(userId) {
val profile = api.fetchProfile(userId)
// обновление состояния
}
}
LaunchedEffect(userId) перезапускается, если userId изменился — предыдущая корутина отменяется, новая запускается с новым userId. Это избавляет от ручного управления отменой запросов. DisposableEffect(Unit) — эффект с фиксированным ключом Unit, срабатывает при входе в композицию и вызывает onDispose при выходе. SensorReader регистрирует слушатель и отписывается при уходе с экрана — без риска утечки.
Если корутину нужно запустить не при входе в композицию, а по событию (нажатие кнопки), используется rememberCoroutineScope(). Он возвращает CoroutineScope, привязанный к жизненному циклу Composable, не требующий DisposableEffect. Пример: запуск сетевого запроса при клике на кнопку — scope.launch { viewModel.loadData() }.
Выбор между Compose и View System — главный архитектурный вопрос Android-разработчика в 2026 году. Обе технологии поддерживаются Google, но Compose — основное направление, на которое Google тратит ресурсы. View System получает только критические исправления и не развивается. Разница проявляется в синтаксисе, управлении состоянием, производительности и времени разработки.
| Аспект | Jetpack Compose | View System |
|---|---|---|
| Описание UI | Kotlin @Composable функции | XML-разметка + Activity/Fragment |
| Состояние | mutableStateOf, StateFlow, автоматическая перерисовка | findViewById, вручную: setText, notifyDataSetChanged |
| Производительность | Intelligent recomposition, Canvas-рендеринг | View-иерархия, measure/layout/draw |
| Анимации | animate*AsState, AnimatedVisibility, встроенные | ValueAnimator, ObjectAnimator, Transition |
| Совместимость | minSdk 21, ComposeView/AndroidView мосты | Все версии, любая |
| Размер APK | +3–5 МБ на Compose | Без накладных расходов |
Для новых проектов Google рекомендует Jetpack Compose как стандарт UI-разработки. View System остаётся для поддержки кода, написанного до 2021 года, и случаев, когда требуется минимальный размер APK (например, для развивающихся рынков с устройствами начального уровня). Compose сокращает объём UI-кода на 30–50% по сравнению с View System за счёт декларативного синтаксиса и встроенной анимации.
Часто задаваемые вопросы
Да, через ComposeView в XML-разметке. Добавьте dependency на Compose и оберните экран или его часть в ComposeView { MyComposable() }. Миграция поэкранная.
Причина — состояние поднимается слишком высоко или используются изменяемые объекты. Исправление: derivedStateOf для производных данных и remember для стабильных ссылок.
Используйте LazyColumn (аналог RecyclerView). Элементы создаются и переиспользуются по мере скролла. Для сложных списков с разными типами ячеек — LazyColumn { items(items, key = { it.id }) { ... } }.
Нет, можно начинать сразу с Compose. Знание View System помогает при поддержке легаси-кода, но Compose — самостоятельная экосистема со своей документацией и паттернами.
Да, Material 3 — стандартная тема Compose с 2023 года. Подключается через implementation("androidx.compose.material3:material3"). Material 2 считается устаревшим.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.