Мобильные приложенияJava / Kotlin

Как сделать первое Android-приложение на Kotlin и Jetpack Compose

Создаём экран в Jetpack Compose с полем, кнопкой и состоянием, запускаем Preview и эмулятор, а затем разбираем recomposition и сохранение данных.

Кодик

Автор

6 мин чтения

Jetpack Compose строит Android-интерфейс из Kotlin-функций: состояние меняется, а нужная часть экрана пересчитывается автоматически. Создадим Empty Activity, добавим поле имени, кнопку и приветствие. Проект заработает в Preview и на эмуляторе, а rememberSaveable сохранит введённые данные при повороте экрана.

Первый Android-проект пугает количеством файлов, хотя пользовательский сценарий маленький. Activity является точкой входа, setContent запускает Compose, а composable-функция описывает текущий вид экрана. Поле ввода не изменяет Text напрямую: оно обновляет переменную state. Compose замечает изменение и выполняет recomposition.

1Создаём проект

Empty Activity готовит Kotlin, Compose, тему и конфигурацию сборки.

2Храним состояние

rememberSaveable держит имя и приветствие между recomposition и поворотом.

3Проверяем

Preview показывает компоновку быстро, эмулятор подтверждает ввод, клавиатуру и lifecycle.

Как Activity, Compose и state связаны между собой

Android Studio создаёт проект из Empty Activity. В onCreate вызывается setContent, внутри темы запускается GreetingScreen. Два состояния хранят введённое name и готовую строку greeting. OutlinedTextField получает value и onValueChange, поэтому является контролируемым полем. Button по клику очищает пробелы и формирует приветствие или подсказку.

ЭтапЧто происходитПризнак результата
ActivityonCreate запускает setContentCompose tree создан
StateПоле меняет name через onValueChangeПеременная обновлена
RecompositionCompose перечитывает затронутые composableUI показывает новое значение
DeviceЭмулятор запускает APK и lifecycleПоворот сохраняет state

У проекта есть один главный маршрут: получить входные данные, проверить их, выполнить действие и показать результат. Если каждый этап можно проверить отдельно, ошибка перестаёт быть загадкой.

Как state обновляет Compose UI
От входных данных до видимого результата. Событие меняет данные, Compose приводит UI в соответствие

Начните с шаблона текущей Android Studio. Compose и Gradle быстро развиваются. Новый Empty Activity создаёт совместимые версии и правильную структуру. Не заменяйте build-файлы случайным фрагментом, если задача только в первом экране.

Собираем экран с полем и кнопкой

Установите актуальную Android Studio, выберите New Project, затем Empty Activity, Kotlin и поддерживаемый minimum SDK. Дождитесь Gradle Sync. Откройте MainActivity.kt и замените содержимое экрана на пример ниже, сохранив package и тему своего проекта. Preview можно запустить из редактора, а для устройства создайте эмулятор в Device Manager.

@Composable
fun GreetingScreen(modifier: Modifier = Modifier) {
    var name by rememberSaveable { mutableStateOf("") }
    var greeting by rememberSaveable { mutableStateOf("Введите имя") }

    Column(
        modifier = modifier
            .fillMaxSize()
            .padding(24.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("Первое приложение", style = MaterialTheme.typography.headlineMedium)
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Ваше имя") },
            singleLine = true
        )
        Button(onClick = {
            val cleanName = name.trim()
            greeting = if (cleanName.isEmpty()) "Сначала введите имя" else "Привет, $cleanName!"
        }) {
            Text("Поздороваться")
        }
        Text(greeting, style = MaterialTheme.typography.titleLarge)
    }
}
Что должно произойти после запуска
  • Preview показывает поле, кнопку и начальную подсказку без запуска эмулятора.
  • Ввод имени сразу обновляет state поля, но приветствие меняется только по кнопке.
  • Пустое имя после trim даёт понятное сообщение.
  • После поворота эмулятора name и greeting сохраняются благодаря rememberSaveable.

Экран является функцией от состояния. Мы не ищем Text по id и не присваиваем ему значение вручную. Меняется greeting, после чего Compose приводит интерфейс в соответствие.

Ручное изменение View и декларативный экран
Что отличает устойчивый проект от случайного успеха. Один источник состояния упрощает объяснение экрана

Почему интерфейс перерисовывается без ручного поиска View

mutableStateOf создаёт наблюдаемое состояние. Когда composable читает name или greeting, Compose запоминает зависимость. Изменение значения планирует recomposition затронутой части дерева. remember удерживает значение между recomposition, но может потерять его при пересоздании Activity.

ЧастьОтветственностьЧто проверить
ComponentActivityВходит в Android lifecyclesetContent вызывается один раз
ComposableОписывает экран для текущего stateНе меняет View вручную
mutableStateOfХранит наблюдаемое значениеИзменение вызывает recomposition
rememberSaveableСохраняет простое UI-stateПоворот не очищает поле
PreviewПоказывает функцию в редактореНе заменяет тест на устройстве

Recomposition не обязана выполнять весь экран и не означает полную перерисовку пикселей. Compose может пропускать части, входы которых не изменились. Поэтому composable должна быть быстрой и без неожиданных побочных эффектов. Не запускайте сетевой запрос прямо в теле функции: при recomposition он повторится.

Preview не запускает весь Android lifecycle. Он удобен для размеров, текста и темы, но клавиатуру, поворот, back button и реальное устройство проверяйте на эмуляторе или телефоне.

Проверяем Preview, поворот и пустой ввод

Запустите Preview и измените текст заголовка. Затем установите приложение на эмулятор, введите имя и поверните экран. Убедитесь, что оба значения сохранились. Замените rememberSaveable на remember, повторите поворот и сравните. Верните saveable. Добавьте счётчик приветствий как Int и вывод «Нажатий: N». После этого ограничьте имя 30 символами в onValueChange.

Проверка своими руками
  1. Создайте Empty Activity и дождитесь успешного Gradle Sync.
  2. Покажите GreetingScreen в Preview.
  3. Запустите эмулятор и проверьте пустое и обычное имя.
  4. Сравните remember и rememberSaveable при повороте.
  5. Добавьте счётчик кликов с типом Int.
  6. Проверьте экран в светлой и тёмной системной теме.
Готово, если выполняются все пункты
  • Проект собирается из текущего шаблона.
  • Preview и эмулятор показывают один экран.
  • Пустой ввод обработан.
  • Состояние переживает поворот.

Первое приложение готово, когда вы можете предсказать, какая переменная изменится после каждого события и почему экран обновится. Кнопка и красивый Preview без понимания state дают слишком хрупкую основу.

Четыре проверки первого Android-приложения
Четыре проверки перед следующим шагом. Preview и эмулятор отвечают на разные вопросы

Готовим приложение к следующему экрану

Дальше вынесите state и обработчики в параметры GreetingScreen, чтобы composable было проще тестировать. Затем добавьте ViewModel и разделите UI-state от событий. Для второго экрана используйте Navigation Compose только после того, как первый экран не хранит бизнес-логику внутри кнопки.

Как изучить тему в Кодике

В Кодике сначала закрепите переменные, функции и классы Kotlin. Затем напишите чистую функцию, которая принимает name и возвращает greeting. Только после этого подключите её к state и кнопке Compose.

ШагЧто изучить в КодикеМини-проверка
1Строки и функции KotlinСформировать greeting из cleanName
2Условия и null safetyОбработать пустой ввод
3Composable и ModifierСобрать Column с отступами
4State и событияСвязать value и onValueChange
5Lifecycle UI-stateСравнить remember и rememberSaveable

Не пытайтесь запомнить весь API. В тренажёре Кодика сначала воспроизведите чистую логику без библиотеки, затем восстановите подключение и обработку ошибок. Финальный тест: объяснить проект по памяти и добавить одну свою функцию.

Скопирован старый build.gradle

Используйте актуальный Empty Activity и меняйте экран, не ломая согласованные версии.

Сетевой запрос запускается в теле composable

Recomposition может повторить вызов. Используйте архитектурный слой и API эффектов.

Всё состояние хранится в Text

UI должен читаться из state, а события изменяют state, не отдельные View.

Проверяется только Preview

Запустите эмулятор для клавиатуры, поворота и lifecycle.

Сверьтесь с первичным источником. Команды, версии и ограничения примера проверяйте по официальному codelab Android: первое Compose-приложение. Если интерфейс изменился, первичная документация важнее старого скриншота.

Что получится в итоге

Готовый результат: Как сделать первое Android-приложение на Kotlin и Jetpack Compose
Первый Android-экран принимает имя, обновляет state по кнопке, переживает поворот и одинаково выглядит в Preview и на эмуляторе.

Короткие ответы
Что запускает recomposition?

Изменение наблюдаемого state, который был прочитан composable-функцией.

Чем rememberSaveable отличается от remember?

Он может восстановить поддерживаемое простое значение после пересоздания Activity, например при повороте.

Зачем нужен Preview, если есть эмулятор?

Preview ускоряет визуальную работу, а эмулятор проверяет lifecycle, ввод и поведение реального Android.

Как понять, что проект действительно работает?

Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.

Можно ли начать с готового кода из статьи?

Да. Добейтесь результата, измените одно правило и соберите ключевой файл заново без копирования.

Освойте state на одном экране до навигации и базы

Функции, классы и условия закрепите в курсе Java и Kotlin. Ошибки объектов сравните с материалом про NullPointerException.

Проект сохраните через GitHub, а идею быстрого мобильного прототипа сравните со статьёй про мобильное приложение с ИИ.