- Создавать sealed-класс и обрабатывать его в
whenбезelse - Объяснять роль
suspend,launch,async/awaitиdelay - Читать простую
@Composable-функцию и понимать, как экран обновляется при изменении состояния
Ты открываешь мессенджер: сначала крутится индикатор загрузки, потом появляются сообщения, а если нет интернета — уведомление об ошибке. При этом экран не зависает — можно листать и нажимать кнопки. За этим стоят три возможности Kotlin: sealed-классы, описывающие состояния, корутины, выполняющие работу в фоне, и Jetpack Compose, который рисует экран. Этот урок — твой первый шаг в мир Android.
Sealed-классы: закрытое семейство
Все дочерние классы sealed («запечатанного») класса известны заранее и объявлены в том же пакете — добавить новый наследник где-то ещё нельзя. Это идеально для описания фиксированного набора вариантов вроде «загрузка / успех / ошибка». Каждый вариант может нести свои данные: причину ошибки, результат успеха. Для варианта без данных используют data object.
sealed class UiState {
data object Loading : UiState()
data class Success(val messages: Int) : UiState()
data class Error(val reason: String) : UiState()
}
fun render(state: UiState): String = when (state) {
UiState.Loading -> "Loading..."
is UiState.Success -> "You have ${state.messages} new messages"
is UiState.Error -> "Error: ${state.reason}"
}
fun main() {
val states = listOf(UiState.Loading, UiState.Success(5), UiState.Error("No internet"))
states.forEach { println(render(it)) }
println(UiState.Success(5))
}Loading... You have 5 new messages Error: No internet Success(messages=5)
Обрати внимание: в выражении when нет ветки else. Компилятор знает, что у UiState всего три варианта, и проверяет, что обработаны все. А в ветке is UiState.Success работает умное приведение типа — state.messages доступно напрямую.
Корутины: ждать, не замораживая
В Android-приложении экран рисует главный поток (main thread). Загрузка данных из интернета может занять несколько секунд; если всё это время главный поток будет ждать, экран зависнет. Корутины решают эту проблему: корутина может приостановиться (suspend) посреди работы, освободить поток для других задач и продолжить, когда придёт ответ. Корутины очень лёгкие — одновременно могут работать тысячи.
suspend fun— функция, которая может приостанавливаться. Её можно вызвать только из корутины или из другойsuspend-функции.delay(1000)приостанавливает корутину на 1 секунду, но не блокирует поток.launch { }запускает новую корутину, результат которой не ждут («запустил и забыл»).async { }запускает корутину с результатом; результат получают черезawait().runBlocking { }связывает обычную функциюmainс миром корутин; он нужен только для примеров и тестов.
import kotlinx.coroutines.*
suspend fun fetchTemperature(city: String): Int {
delay(1000)
return if (city == "Baku") 24 else 19
}
fun main() = runBlocking {
println("Loading...")
launch {
delay(500)
println("Half a second passed")
}
val baku = async { fetchTemperature("Baku") }
val ganja = async { fetchTemperature("Ganja") }
println("Baku: ${baku.await()}, Ganja: ${ganja.await()}")
println("Done")
}Loading... Half a second passed Baku: 24, Ganja: 19 Done
kotlinx-coroutines-core. Два запроса выполняются параллельно, поэтому программа работает около 1 секунды, а не 2.Вкус Android: Jetpack Compose
Jetpack Compose — современный набор инструментов Google для создания интерфейсов Android на Kotlin. Вместо того чтобы менять экран шаг за шагом, ты описываешь, как он должен выглядеть, — такой подход называется декларативным. Каждая часть экрана — обычная функция Kotlin, помеченная аннотацией @Composable. Код ниже — часть Android-проекта, отдельно его запустить нельзя:
@Composable
fun Greeting(name: String) {
var count by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.padding(16.dp)) {
Text(text = "Hello, $name!")
Button(onClick = { count++ }) {
Text("Clicked $count times")
}
}
}
@Preview
@Composable
fun GreetingPreview() {
Greeting("Aysel")
}@Composableговорит, что функция описывает часть интерфейса. Такие имена пишут с заглавной буквы:Greeting.remember { mutableIntStateOf(0) }создаёт состояние (state): Compose запоминает его значение и следит за ним.Columnрасполагает элементы вертикально, аModifier.padding(16.dp)добавляет отступы по краям.Button(onClick = { count++ }) { ... }— знакомая картина: две лямбды! Одна выполняется при нажатии, вторая (последняя лямбда) описывает содержимое кнопки.@Previewпозволяет Android Studio показать превью экрана без запуска приложения на телефоне.
Где же магия? При нажатии на кнопку count меняется. Compose замечает это и снова вызывает функцию Greeting — это называется рекомпозицией (recomposition) — и обновляет только изменившуюся часть экрана. Ты не обновляешь экран вручную, а просто меняешь состояние. Здесь сходятся все прошлые уроки: функции, лямбды, строковые шаблоны и состояния с when.
Главное
- Все варианты sealed-класса известны, поэтому
whenможет охватить их полностью безelse. - Корутина может приостановиться, не блокируя поток;
suspend-функции вызываются только из корутин. launchзапускает работу без результата, аasyncдаёт результат, который получают черезawait().- В Compose интерфейс описывается
@Composable-функциями; при изменении состояния экран обновляется автоматически (рекомпозиция).
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.
when по sealed-классу не нужен else?