Jetpack Compose: основы, Composable функции и State

Автор: IT Sectr Опубликовано: 2026-02-21 Время чтения: 8 мин

Jetpack Compose — современный декларативный UI-фреймворк от Google для Android-разработки, представленный в стабильной версии 1.0 в июле 2021 года. Compose заменяет императивную XML-разметку и View-систему на Kotlin-функции с аннотацией @Composable. По данным Google I/O (2025), Compose используется в 55% новых проектов на Android, а средний размер UI-кода сокращается на 30–50% по сравнению с XML. Фреймворк автоматически перерисовывает только изменившиеся части экрана при изменении State, исключая ручной вызов notifyDataSetChanged или findViewById.

Главное

  • Jetpack Compose — декларативный UI-фреймворк Google для Android на Kotlin (@Composable функции вместо XML-разметки).
  • @Composable — аннотация функции, описывающей часть UI, которая может принимать параметры и читать State.
  • State и MutableState — механизм реактивности: при изменении State Compose перезапускает (recompose) только зависимые Composable-функции.
  • remember — функция кэширования значения между рекомпозициями; без неё State сбрасывается при каждом обновлении.
  • Modifier — цепочка настроек (padding, size, clickable, background), управляющая внешним видом и поведением Composable.

Что такое Jetpack Compose?

Jetpack Compose — UI-фреймворк Google, построенный на принципах реактивного программирования. Вместо Activity с XML-разметкой, FragmentManager, и ViewBinding разработчик описывает интерфейс через Kotlin-функции с аннотацией @Composable. Compose не использует LayoutInflater — UI — это чистые функции Kotlin, компилируемые в байткод. Фреймворк состоит из нескольких библиотек: Compose UI (базовые компоненты Text, Button, Column, Row), Compose Foundation (Material Design, Gestures, Focus), Compose Material3 (Material You с Dynamic Colors) и Compose Runtime (State, Side Effects, Coroutines). Compose работает на Android API 21+ (Android 5.0) и полностью совместим с существующим кодом на View/XML через ComposeView — AndroidView-адаптер.

Compose vs View System

View System (2008) использует иерархию View-объектов с ручным управлением: разработчик создаёт XML-макет, находит View через findViewById, реализует Adapter для RecyclerView и вызывает notifyDataSetChanged при изменении данных. Compose описывает UI функционально: при изменении состояния фреймворк перезапускает (recompose) только изменившиеся Composable-функции, вычисляет diff и применяет минимальные изменения к Canvas. Производительность Compose сопоставима с View System, а в сценариях со сложными списками (LazyColumn) часто превосходит RecyclerView благодаря пропуску лишних элементов через key-параметр. В IT Sectr Compose используется для новых модулей Android-приложений с minSdk 24+.

Composable функции: строительные блоки UI

@Composable — аннотация, превращающая обычную Kotlin-функцию в строительный блок UI. Composable-функции могут вызывать другие Composable-функции, образуя дерево компонентов. В отличие от View, Composable-функции не имеют состояния по умолчанию — они stateless и перерисовываются при каждом изменении входных параметров или State. Компоновщик (Compose Compiler) трансформирует @Composable-функции в код, который может быть прерван и возобновлён (positional memoization) — это позволяет Compose перезапускать только изменившиеся части без полного перестроения дерева.

kotlin
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun UserProfile(name: String, avatarUrl: String) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        AsyncImage(
            model = avatarUrl,
            contentDescription = "User avatar",
            modifier = Modifier.size(48.dp)
        )
        Spacer(modifier = Modifier.width(12.dp))
        Text(
            text = name,
            style = MaterialTheme.typography.titleMedium
        )
    }
}

Функция UserProfile принимает name и avatarUrl как параметры, строит строку с аватаром и именем. Modifier.fillMaxWidth() растягивает компонент на всю ширину, .padding(16.dp) добавляет отступы. MaterialTheme.typography.titleMedium использует системный стиль Material 3. При изменении параметров name или avatarUrl Compose перезапускает UserProfile — повторное создание компонента с новыми значениями.

State и Recomposition в Jetpack Compose

State в Compose — это любое значение, изменение которого вызывает рекомпозицию (перезапуск) зависимых @Composable-функций. Базовый способ — mutableStateOf(), создающий MutableState<T> с поддержкой snapshot-системы Compose. Snapshot — механизм отслеживания изменений: при записи в State Compose помечает текущий Snapshot как dirty, и планировщик рекомпозиции перезапускает только Composable-функции, читающие этот State. Для observable-коллекций используйте mutableStateListOf() и mutableStateMapOf(). Compose поддерживает State из Lifecycle-Aware компонентов через collectAsState() для Kotlin Flow и observeAsState() для LiveData.

kotlin
@Composable
fun LikeButton() {
    var liked by remember { mutableStateOf(false) }
    var count by remember { mutableStateOf(42) }
    
    Button(
        onClick = {
            liked = !liked
            if (liked) count++ else count--
        },
        colors = ButtonDefaults.buttonColors(
            containerColor = if (liked) MaterialTheme.colorScheme.primary
                else MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Text("♥ $count")
    }
}

Код создаёт кнопку «Like» с состоянием liked (Boolean) и count (Int), хранящимися через mutableStateOf(). При нажатии liked инвертируется, счётчик увеличивается/уменьшается — Compose автоматически перезапускает LikeButton. by delegate позволяет использовать State как обычную переменную: liked = !liked вместо liked.value = !liked.value. Цвет кнопки реактивно меняется между primary (лайкнуто) и surfaceVariant (не лайкнуто).

remember: кэширование между рекомпозициями

remember — функция Compose, кэширующая значение между рекомпозициями. Без remember каждый перезапуск Composable-функции создаёт новое состояние (mutableStateOf) — это ломает логику приложения: при повороте экрана или изменении родительского State счётчик сбросится. remember принимает лямбду-калькулятор и вычисляет значение только на первой композиции; на последующих возвращает кэшированный результат. Для сброса кэша используйте remember(key) — ключ определяет, когда пересчитать значение. remember(key1, key2) пересчитывает при изменении любого ключа. Для долгоживущих состояний (переживающих поворот экрана) используйте rememberSaveable — аналог remember с сохранением в Bundle через SavedStateHandle.

kotlin
@Composable
fun TimerScreen() {
    var seconds by rememberSaveable { mutableStateOf(0) }
    
    LaunchedEffect(Unit) {
        while (true) {
            delay(1000)
            seconds++
        }
    }
    
    Column(
        modifier = Modifier.fillMaxSize().padding(32.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Elapsed: ${seconds}s",
            style = MaterialTheme.typography.displayMedium
        )
    }
}

rememberSaveable сохраняет seconds при повороте экрана (конфигурационное изменение). LaunchedEffect запускает корутину, инкрементирующую seconds каждую секунду. При рекомпозиции TimerScreen (каждую секунду) seconds не сбрасывается благодаря rememberSaveable. Используйте обычный remember для состояния, которое не должно переживать конфигурационные изменения (например, анимационные флаги).

Modifier: цепочка настроек Composable

Modifier — иммутабельный объект-контейнер, реализующий паттерн Builder для настройки внешнего вида, поведения и разметки Composable-компонентов. Каждый вызов метода Modifier (.padding(), .width(), .clickable(), .background()) возвращает новый Modifier с добавленным элементом. Порядок модификаторов имеет значение: .padding(16.dp).clickable { } — отступ применяется до обработчика клика, clickable отслеживает всю область с учётом отступа. .clickable { }.padding(16.dp) — кликабельна вся область до отступа, отступ смещает контент внутрь. Modifier поддерживает кастомные реализации через then(otherModifier) и compositionLocal для доступа к родительским настройкам.

kotlin
@Composable
fun CardExample() {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
            .clickable { println("Card clicked") },
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text("Jetpack Compose", style = MaterialTheme.typography.titleLarge)
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                "Декларативный UI для Android с State и Modifier",
                style = MaterialTheme.typography.bodyMedium
            )
        }
    }
}

CardExample демонстрирует цепочку Modifier: fillMaxWidth + padding + clickable. Card — Material3-компонент с собственной настройкой elevation и colors. Вложенный Column имеет внутренний padding 16dp. Compose Material3 автоматически адаптирует цвета под Dynamic Color (Material You) на Android 12+. Card — один из 30+ встроенных Material3-компонентов в Compose.

State hoisting и архитектура Compose

State hoisting — паттерн подъёма состояния из Composable-функции в её caller, делающий функцию stateless. Stateless-компонент принимает данные и колбэки через параметры, не владея State самостоятельно. Это повышает переиспользуемость и тестируемость: компонент можно вызвать с разными State и проверить в preview. Google рекомендует архитектуру: ViewModel + StateFlow (или MutableStateFlow) + collectAsState() в Compose. ViewModel поднимает состояние на уровень экрана, Compose отображает. Side-эффекты (LaunchedEffect, DisposableEffect) обрабатывают одноразовые события.

КомпонентОбязанностьТехнология
ViewModelХранение State, бизнес-логикаStateFlow, MutableStateFlow
Screen ComposableОрганизация экрана, State hoistingcollectAsState(), Scafold, LazyColumn
Stateless ComponentUI без состояния, чистое отображение@Composable параметры + лямбды
Side EffectОдноразовые действия (snackbar, navigation)LaunchedEffect, SnackbarHostState

Часто задаваемые вопросы

Чем Jetpack Compose отличается от XML-верстки?

XML-верстка императивна: LayoutInflater загружает XML, findViewById находит View, разработчик вручную обновляет текст/списки. Compose декларативен: UI описывается Kotlin-функциями @Composable, а фреймворк автоматически перерисовывает только изменившиеся части при изменении State. Compose сокращает объём UI-кода на 30–50% и не использует XML.

Нужна ли отдельная библиотека для навигации в Compose?

Да, Google предоставляет Navigation Compose — библиотеку для декларативной навигации между экранами. NavController управляет стеком маршрутов, composable() регистрирует экраны, navArgument передаёт параметры. Альтернативы: Voyager (community) и Decompose (Badoo). Navigation Compose — официальный стандарт с поддержкой deep links и type-safe аргументов.

Что такое Modifier в Jetpack Compose?

Modifier — иммутабельный контейнер паттернов оформления (padding, size, clickable, background, border, clip), применяемых к Composable-компонентам. Каждый вызов возвращает новый Modifier с добавленным элементом. Порядок важен: .padding().clickable() применяет отступ до клика, .clickable().padding() — наоборот. Modifier — основной способ кастомизации Compose-компонентов.

Compose работает на всех версиях Android?

Jetpack Compose поддерживает Android API 21+ (Android 5.0 Lollipop) через Compose Compiler и Compose BOM. Material 3 (Dynamic Colors) доступна на Android 12+; на более старых версиях используется fallback-палитра. Для новых проектов Apple рекомендует minSdk 24+ (Android 7.0), что полностью покрывается Compose.

Как тестировать Compose-компоненты?

Google предоставляет Compose UI Test — библиотеку для тестирования на JVM (Desktop) и эмуляторе. Основные функции: composeTestRule.setContent { } для отрисовки компонента, onNodeWithText() для поиска элементов, performClick()/performTextInput() для действий. Espresso-тесты совместимы с Compose через ComposeTestRule, но Compose UI Test — предпочтительный и более быстрый подход.

Итоги

  • Jetpack Compose — декларативный UI-фреймворк Google для Android с Kotlin @Composable функциями вместо XML (стабилен с 2021).
  • @Composable — аннотация, превращающая Kotlin-функцию в UI-компонент; дерево Composable-функций заменяет иерархию View.
  • State и mutableStateOf — основа реактивности Compose через Snapshot-систему; рекомпозиция затрагивает только зависимые функции.
  • remember кэширует значение между рекомпозициями; rememberSaveable сохраняет State при конфигурационных изменениях.
  • Modifier — цепочка настроек (padding, size, clickable, background), образующая иммутабельный контейнер; порядок модификаторов важен.
  • State hoisting — паттерн подъёма состояния вверх для stateless-компонентов; ViewModel + StateFlow + collectAsState() — рекомендуемая архитектура.
  • Material 3 c Dynamic Colors (Android 12+) — стандартная тема Compose с автоматической адаптацией под обои устройства.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также