Що ви опануєте
Ця лекція формує базову систему понять, яка знадобиться для всього подальшого курсу. Ми розглянемо, як влаштована Android-платформа, які інструменти беруть участь у створенні застосунку, як Kotlin-код потрапляє на пристрій, як формується інтерфейс у Jetpack Compose та як Android керує життєвим циклом компонентів.
Після опрацювання матеріалу ви зможете:
- пояснити, що таке мобільний застосунок і які задачі він розв’язує;
- описати базові рівні Android-платформи;
- пояснити призначення Android Studio, Android SDK, Gradle, ADB та Android Emulator;
- орієнтуватися у структурі Android-проєкту;
- читати базовий Kotlin-код;
- пояснити роль
Activity; - створити простий UI за допомогою Jetpack Compose;
- пояснити поняття
Composable, state та recomposition; - розуміти призначення ресурсів Android;
- пояснити, як працюють дозволи;
- описати основні етапи життєвого циклу
Activity; - запускати застосунок на емуляторі або фізичному пристрої;
- використовувати Logcat для базової діагностики.
Що таке мобільний застосунок
До таких пристроїв належать:
- смартфони;
- планшети;
- смарт-годинники;
- телевізори;
- автомобільні мультимедійні системи;
- складні пристрої;
- спеціалізовані термінали;
- вбудовані Android-пристрої.
Мобільний застосунок може використовувати системні можливості:
- камеру;
- мікрофон;
- геолокацію;
- Bluetooth;
- NFC;
- Wi-Fi;
- файлову систему;
- сенсори;
- сповіщення;
- біометричну автентифікацію;
- локальне сховище;
- мережу;
- фонові задачі.
Мобільне середовище має власні обмеження: обсяг пам’яті, заряд акумулятора, нестабільність мережі, різні розміри екранів, зміну орієнтації, фонове призупинення процесів і контроль доступу до приватних даних.
Основні підходи до мобільної розробки
Мобільні застосунки можуть створюватися кількома способами.
Нативна розробка
Нативний Android-застосунок створюється для Android-платформи з використанням її SDK, API та інструментів. Для сучасної Android-розробки основною мовою є Kotlin.
Нативний підхід дає прямий доступ до Android API, камери, сенсорів, геолокації, push-сповіщень, локального сховища, системних сервісів і життєвого циклу Android-компонентів.
Кросплатформна розробка
Кросплатформні технології дозволяють створювати спільну кодову базу для кількох платформ.
Приклади:
- Flutter;
- React Native;
- Kotlin Multiplatform;
- .NET MAUI.
У цьому курсі основна увага приділяється нативній Android-розробці на Kotlin та сучасному UI на Jetpack Compose.
Що таке Android
Android використовується на великій кількості типів пристроїв і має багаторівневу архітектуру.
Найвищий рівень, з яким взаємодіє користувач.
Linux Kernel
Ядро Linux відповідає за базові функції операційної системи:
- керування процесами;
- керування пам’яттю;
- роботу драйверів;
- мережеву взаємодію;
- файлову систему;
- енергоспоживання;
- базові механізми безпеки.
Native Libraries
Системні бібліотеки реалізують графіку, роботу з медіа, базами даних, шифруванням, файлами та іншими низькорівневими функціями.
Android Runtime
ART відповідає за виконання скомпільованого коду та взаємодіє із системними механізмами керування пам’яттю й процесами.
Application Framework
Application Framework надає API для:
Activity;- ресурсів;
- сповіщень;
- геолокації;
- дозволів;
- вікон;
- пакетів;
- фонових задач;
- системних служб.
Як Android ізолює застосунки
Кожен застосунок має власний простір даних та системну ідентичність. Це допомагає захищати приватність користувача, файли та системні ресурси.
Android Studio
Android Studio об’єднує:
- редактор Kotlin-коду;
- Android SDK;
- Gradle;
- систему підказок;
- статичний аналіз;
- Device Manager;
- Android Emulator;
- Logcat;
- debugger;
- profiler;
- редактори ресурсів;
- Compose Preview;
- засоби тестування.
Середовище розробки.
Android SDK
Android SDK містить:
- Android Platform API;
- Build Tools;
- Platform Tools;
- ADB;
- Emulator;
- системні образи;
- утиліти пакування;
- інструменти командного рядка.
Рівні API
Кожна версія Android має номер API level.
android {
compileSdk = 36
defaultConfig {
minSdk = 24
targetSdk = 36
}
}
compileSdk
compileSdk визначає версію Android API, відносно якої компілюється проєкт.
minSdk
minSdk визначає мінімальний API level, на якому застосунок дозволено встановлювати.
targetSdk
targetSdk визначає рівень платформи, під правила поведінки якого підготовлений застосунок.
Gradle
- Крок 1 із 6
Читання конфігурації
Gradle аналізує налаштування проєкту та модулів.
- Крок 2 із 6
Завантаження залежностей
Потрібні бібліотеки отримуються з налаштованих репозиторіїв.
- Крок 3 із 6
Компіляція
Kotlin-код проходить компіляцію.
- Крок 4 із 6
Обробка ресурсів
Ресурси Android включаються до збірки.
- Крок 5 із 6
Пакування
Формується APK або інший артефакт.
- Крок 6 із 6
Встановлення
Пакет передається на емулятор або фізичний пристрій.
Залежності
dependencies {
implementation("androidx.activity:activity-compose:...")
implementation("androidx.compose.material3:material3:...")
}
implementation повідомляє Gradle, що модуль використовує вказану бібліотеку.
Що відбувається після Run
Код у .kt файлах.
APK та AAB
APK містить скомпільований код, ресурси, manifest, метадані та бібліотеки.
Структура Android-проєкту
MyApplication/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/example/myapplication/
│ │ │ │ └── MainActivity.kt
│ │ │ ├── res/
│ │ │ │ ├── drawable/
│ │ │ │ ├── mipmap/
│ │ │ │ ├── values/
│ │ │ │ └── xml/
│ │ │ └── AndroidManifest.xml
│ │ ├── test/
│ │ └── androidTest/
│ └── build.gradle.kts
├── gradle/
├── build.gradle.kts
├── settings.gradle.kts
└── gradle.properties
Модуль app
app — основний модуль застосунку. Він містить Kotlin-код, ресурси, AndroidManifest, залежності, конфігурацію Android та тести.
Каталог src/main
src/main містить код та ресурси основної версії застосунку.
Каталог res
res містить ресурси: рядки, кольори, зображення, іконки, шрифти та XML-конфігурації.
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:theme="@style/Theme.MyApplication">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Що тут відбувається?
<manifest>— кореневий елемент.<application>описує застосунок.<activity>реєструє Activity.android:nameмістить ім’я класу Activity.MAINпозначає основну точку запуску.LAUNCHERдозволяє запускати Activity через іконку застосунку.
Kotlin у контексті Android
val studentName: String = "Олена"
val courseNumber: Int = 2
val rating: Double = 91.5
val isActive: Boolean = true
Основні типи:
String;Int;Long;Float;Double;Boolean;Char.
val і var
val university = "ДДТУ"
var completedLabs = 2
completedLabs = 3
val використовується для значення, яке не переприсвоюється.
var використовується для значення, яке може змінюватися.
Виведення типу
val name = "Анастасія"
val age = 20
val progress = 0.75
Компілятор визначає тип автоматично. Це називається type inference — виведення типу.
Функції Kotlin
fun greet(name: String): String {
return "Вітаю, $name!"
}
Що тут відбувається?
funоголошує функцію.greet— ім’я функції.name: String— параметр.Stringпісля дужок — тип результату.returnповертає результат.$nameвставляє значення змінної в рядок.
Умови та when
fun getStatus(score: Int): String {
return if (score >= 60) {
"Зараховано"
} else {
"Потрібне доопрацювання"
}
}
fun getGrade(score: Int): String {
return when {
score >= 90 -> "Відмінно"
score >= 75 -> "Добре"
score >= 60 -> "Задовільно"
else -> "Потрібне доопрацювання"
}
}
Nullable типи
var userName: String? = null
Безпечне звернення:
val length = userName?.length
Значення за замовчуванням:
val displayName = userName ?: "Гість"
Колекції
val topics = listOf(
"Kotlin",
"Compose",
"Navigation",
"Room"
)
for (topic in topics) {
println(topic)
}
Класи та моделі даних
data class Student(
val name: String,
val group: String,
val rating: Double
)
val student = Student(
name = "Олена",
group = "ПЗ-23",
rating = 91.5
)
data class часто використовується для представлення даних у застосунку.
Лямбда-функції
У Compose лямбди зустрічаються постійно.
val onClick = {
println("Кнопку натиснуто")
}
val onNameChanged: (String) -> Unit = { newName ->
println(newName)
}
Activity
package com.example.myapplication
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text(
text = "Привіт, Android!"
)
}
}
}
Що тут відбувається?
MainActivity— клас стартової Activity.ComponentActivity— базовий AndroidX-клас.onCreate()викликається під час створення Activity.super.onCreate()виконує базову ініціалізацію.setContentпередає формування UI Jetpack Compose.Textстворює текстовий UI-компонент.
Життєвий цикл Activity
Основні callbacks:
onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()
Початкова ініціалізація.
Спостереження через Logcat
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("LIFECYCLE", "onCreate")
}
override fun onStart() {
super.onStart()
Log.d("LIFECYCLE", "onStart")
}
override fun onResume() {
super.onResume()
Log.d("LIFECYCLE", "onResume")
}
override fun onPause() {
Log.d("LIFECYCLE", "onPause")
super.onPause()
}
override fun onStop() {
Log.d("LIFECYCLE", "onStop")
super.onStop()
}
override fun onDestroy() {
Log.d("LIFECYCLE", "onDestroy")
super.onDestroy()
}
}
Jetpack Compose
@Composable
fun Greeting(name: String) {
Text(
text = "Вітаю, $name!"
)
}
@Composable
@Composable позначає функцію, яка бере участь у формуванні Compose UI.
Декларативний підхід
Корисна модель:
UI = f(state)
Інтерфейс формується на основі поточного стану даних.
Перший Compose-екран
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun StudentScreen() {
Column(
modifier = Modifier.padding(24.dp)
) {
Text(text = "Програмування мобільних застосунків")
Text(text = "Перша Android-сторінка")
}
}
Що тут відбувається?
StudentScreen()описує UI-компонент.Columnрозташовує дочірні компоненти вертикально.Modifier.padding(24.dp)додає відступ.dp— density-independent pixel.Textвідображає текст.
Базові layout-компоненти Compose
Modifier
Text(
text = "Android",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
)
Порядок Modifier
Порядок модифікаторів впливає на результат. Кожен наступний модифікатор працює з результатом попереднього кроку.
dp та sp
Material 3
Material 3 надає готові компоненти:
Text;Button;Card;TextField;OutlinedTextField;Scaffold;TopAppBar;NavigationBar;FloatingActionButton;AlertDialog.
@Composable
fun SaveButton() {
Button(
onClick = {
println("Збереження")
}
) {
Text(text = "Зберегти")
}
}
State
Приклади state:
- введений текст;
- обрана вкладка;
- список повідомлень;
- поточний користувач;
- стан завантаження;
- стан авторизації;
- кількість товарів;
- вибраний елемент.
mutableStateOf і remember
var count by remember {
mutableStateOf(0)
}
mutableStateOf(0) створює observable state зі стартовим значенням 0.
remember дозволяє Compose зберігати значення між повторними виконаннями composable-функції в межах поточної композиції.
Recomposition
count = 0
Повний приклад лічильника
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun CounterScreen() {
// Стан лічильника.
var count by remember {
mutableStateOf(0)
}
Column(
modifier = Modifier.padding(24.dp)
) {
// Текст залежить від count.
Text(
text = "Натиснуто: $count"
)
Button(
onClick = {
// Зміна state.
count++
}
) {
Text(text = "Натиснути")
}
}
}
Що тут відбувається?
count— observable state.rememberзберігає стан у поточній композиції.Textчитає значення count.Buttonгенерує подію натискання.count++змінює state.- Compose оновлює частини UI, які читають count.
Поле введення
@Composable
fun StudentForm() {
var name by remember {
mutableStateOf("")
}
Column(
modifier = Modifier.padding(24.dp)
) {
OutlinedTextField(
value = name,
onValueChange = { newValue ->
name = newValue
},
label = {
Text("Ім’я студента")
}
)
Text(
text = "Введено: $name"
)
}
}
State hoisting
@Composable
fun StudentScreen() {
var name by remember {
mutableStateOf("")
}
StudentNameInput(
name = name,
onNameChange = { newName ->
name = newName
}
)
}
@Composable
fun StudentNameInput(
name: String,
onNameChange: (String) -> Unit
) {
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = {
Text("Ім’я")
}
)
}
rememberSaveable
Для стану, який має переживати типові відтворення Activity, Compose надає rememberSaveable.
var count by rememberSaveable {
mutableStateOf(0)
}
Preview
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
@Preview(showBackground = true)
@Composable
fun StudentScreenPreview() {
StudentScreen()
}
Preview допомагає перевіряти layout, текст, тему та різні стани UI.
Тема застосунку
MyApplicationTheme {
CourseScreen()
}
Тема може визначати кольори, типографіку, форми, світлу та темну схеми.
Text(
text = "Заголовок",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary
)
Ресурси Android
Android має спеціальну ресурсну систему.
<resources>
<string name="app_name">Mobile Course</string>
<string name="welcome_message">Вітаємо у застосунку</string>
</resources>
У Compose:
Text(
text = stringResource(R.string.welcome_message)
)
Об’єкт R
Android генерує спеціальний клас R.
R.string.app_name
R.drawable.logo
R.color.primary
Локалізація
res/values/strings.xml
res/values-uk/strings.xml
res/values-en/strings.xml
Android вибирає потрібний ресурс відповідно до конфігурації пристрою.
Дозволи Android
<uses-permission
android:name="android.permission.CAMERA" />
- Крок 1 із 5
Декларація
Застосунок описує потрібний permission.
- Крок 2 із 5
Перевірка
Код перевіряє, чи надано доступ.
- Крок 3 із 5
Запит
За потреби Android показує системний діалог.
- Крок 4 із 5
Рішення користувача
Користувач дозволяє або відхиляє доступ.
- Крок 5 із 5
Обробка результату
Застосунок продовжує роботу відповідно до стану permission.
Android Emulator
Емулятор дозволяє тестувати різні версії Android, екрани, орієнтацію, геолокацію, темну тему, мову та мережеві умови.
AVD
AVD включає модель пристрою, розмір екрана, API level, системний образ, архітектуру процесора та параметри пам’яті.
Запуск на фізичному пристрої
- Крок 1 із 6
Увімкнути Developer options
На Android-пристрої активується режим розробника.
- Крок 2 із 6
Увімкнути USB debugging
У Developer options активується налагодження через USB.
- Крок 3 із 6
Підключити пристрій
Телефон під’єднується до комп’ютера.
- Крок 4 із 6
Підтвердити довіру
На пристрої може з’явитися запит на дозвіл налагодження.
- Крок 5 із 6
Обрати device
Android Studio показує пристрій у списку Run targets.
- Крок 6 із 6
Запустити
Застосунок збирається, встановлюється і запускається.
ADB
adb devices
List of devices attached
emulator-5554 device
Logcat
Log.d(
"COURSE",
"MainActivity створено"
)
Основні рівні:
V — verbose
D — debug
I — info
W — warning
E — error
Як читати помилки
- Крок 1 із 6
Знайдіть першу змістовну помилку
Довгий журнал може містити багато похідних повідомлень.
- Крок 2 із 6
Визначте етап
Gradle Sync, компіляція, ресурси, встановлення або runtime.
- Крок 3 із 6
Знайдіть файл і рядок
Компілятор часто показує точне місце проблеми.
- Крок 4 із 6
Перевірте типи
Особливо важливі nullable-типи, параметри та imports.
- Крок 5 із 6
Перевірте залежності
Unresolved reference може бути пов’язаний із відсутньою бібліотекою.
- Крок 6 із 6
Повторіть збірку
Після виправлення запустіть Build або Run.
Compile-time та runtime помилки
val count: Int = "п'ять"
Stack trace
FATAL EXCEPTION: main
java.lang.IllegalStateException: ...
at com.example.mobilecourse.StudentScreen(...)
at com.example.mobilecourse.MainActivity(...)
Під час аналізу шукайте:
- тип винятку;
- повідомлення;
- перший рядок із пакетом вашого застосунку;
- файл;
- номер рядка.
Конфігурації пристрою
Android-застосунок має працювати в різних умовах:
- портретна орієнтація;
- альбомна орієнтація;
- світла тема;
- темна тема;
- інша мова;
- планшет;
- складний пристрій;
- збільшений шрифт;
- багатовіконний режим.
Простий повний екран
package com.example.mobilecourse
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface {
CourseScreen()
}
}
}
}
}
@Composable
fun CourseScreen() {
var completedTopics by remember {
mutableStateOf(0)
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
text = "Програмування мобільних застосунків",
style = MaterialTheme.typography.headlineMedium
)
Text(
text = "Вивчено тем: $completedTopics",
style = MaterialTheme.typography.bodyLarge
)
Button(
onClick = {
completedTopics++
}
) {
Text(text = "Позначити тему")
}
}
}
Архітектура першого навчального застосунку
Android entry point.
У наступних темах до цієї схеми поступово додаватимуться:
ViewModel
Navigation
Repository
REST API
Room
Coroutines
Flow
Dependency Injection
Testing
Типові помилки на старті
Android Studio не бачить SDK
Gradle Sync Failed
Емулятор не запускається
Пристрій не видно в Android Studio
Unresolved reference
Composable invocations can only happen...
Мініексперимент
@Composable
fun LearningScreen() {
var lessonNumber by remember {
mutableStateOf(1)
}
Column(
modifier = Modifier.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(text = "Мобільна розробка")
Text(
text = "Поточна тема: $lessonNumber"
)
Button(
onClick = {
lessonNumber++
}
) {
Text(text = "Наступна тема")
}
}
}
Визначте:
- початкове значення
lessonNumber; - текст після першого запуску;
- текст після одного натискання;
- текст після п’яти натискань;
- змінну state;
- подію, яка змінює state;
- компонент, який залежить від state.
Самоперевірка термінів
01 Що таке Android SDK?Показати відповідь
Набір API та інструментів для створення, збірки, запуску й налагодження Android-застосунків.
02 Для чого використовується Gradle?Показати відповідь
Для автоматизації збірки, конфігурації проєкту та керування залежностями.
03 Що таке Activity?Показати відповідь
Android-компонент із власним життєвим циклом, який представляє точку взаємодії користувача із застосунком.
04 Що означає @Composable?Показати відповідь
Анотація позначає функцію, яка бере участь у побудові Compose UI.
05 Що таке state?Показати відповідь
Дані, значення яких впливає на UI або поведінку застосунку.
06 Що таке recomposition?Показати відповідь
Повторне виконання залежних частин Compose UI після зміни observable state.
07 Що таке AVD?Показати відповідь
Конфігурація віртуального Android-пристрою.
08 Що таке Logcat?Показати відповідь
Система перегляду журналів Android і повідомлень застосунку.
09 Що таке APK?Показати відповідь
Пакет Android-застосунку, який може бути встановлений на пристрій.
Перевірка розуміння
Питання для самоперевірки
Навіщо Android-проєкту потрібен AndroidManifest.xml?
Чому Compose потрібен state?
Що відбувається після натискання Run в Android Studio?
Практична перевірка після лекції
Карта понять
Операційна система та платформа.
Джерела для подальшого вивчення
- Android Developers — Get started
- Android Developers — Jetpack Compose
- Android Developers — Activity lifecycle
- Android Developers — App resources
- Android Developers — Permissions
- Android Developers — Android Studio
- Android Developers — Build your app with Gradle
- Kotlin Documentation — Basic syntax
- Kotlin Documentation — Null safety