Що ви опануєте
Ви навчитеся моделювати переходи між екранами, передавати мінімальні аргументи та визначати тривалість життя стану. Приклад — список навчальних тем і сторінка конкретної теми. Навігація має підтримувати очікуване повернення назад, відновлення після зміни конфігурації та коректний результат для невідомого ID.
Екран, маршрут і стек
Destination — місце навігації, яке показує визначений вміст. Route ідентифікує destination та потрібні аргументи. Back stack зберігає історію доступних повернень. NavController координує навігацію, NavHost показує поточну destination. Перехід додає запис за погодженими правилами; повернення зазвичай вилучає верхній.
Для деталей передавайте стабільний ID, а потрібний об’єкт отримуйте з джерела даних. Передавання всього змінюваного об’єкта може створити дві неузгоджені копії. Назва теми може змінитися, ID — залишитися. Якщо ID не знайдений, destination повинна показати зрозумілий стан і можливість повернення.
Navigation Compose
Для прикладів цього курсу використовуємо Navigation Compose 2.x. Залежність із поточної документації — androidx.navigation:navigation-compose:2.10.2. Її додають до app dependencies у Compose проєкті з підтримуваним SDK. Строкові маршрути в навчальному прикладі не потребують serialization plugin; type-safe routes є окремим сучасним варіантом із власною конфігурацією.
@Composable
fun StudyNavigation() {
val controller = rememberNavController()
NavHost(controller, startDestination = "topics") {
composable("topics") {
Button(onClick = { controller.navigate("topic/1") }) {
Text("Відкрити Kotlin")
}
}
composable("topic/{id}", arguments = listOf(
navArgument("id") { type = NavType.IntType }
)) { entry ->
val id = entry.arguments?.getInt("id")
Column {
Text(if (id == 1) "Kotlin" else "Тему не знайдено")
Button(onClick = { controller.popBackStack() }) { Text("Назад") }
}
}
}
}
Фрагмент потребує imports androidx.navigation., androidx.navigation.compose., Compose layout/runtime/Material3. rememberNavController зберігає controller у composition. NavArgument задає тип аргументу. navigate відкриває destination, popBackStack повертає попередню. Приклад має один відомий ID; у реальній моделі замініть умовний Text на пошук за джерелом із визначеною політикою відсутності.
Повторні переходи
Кілька швидких натискань можуть додати однакові destination. launchSingleTop для потрібного переходу дозволяє не створювати ще один верхній запис тієї самої destination за визначених умов. Для top-level навігації застосовують також popUpTo, saveState та restoreState з поясненим контрактом. Вони змінюють історію, тому їх не потрібно додавати до кожного переходу автоматично.
Розрізняйте «назад» та «до розділу». Повернення проходить історію користувача; дія до розділу може вести у визначену destination. Deep link відкриває конкретний вміст із зовнішнього контексту, тому початковий стек може відрізнятися. Потрібно перевірити навігацію і з головного екрана, і з прямого входу.
Activity lifecycle
Activity проходить callbacks створення, видимості, активності, паузи та зупинки. OnCreate готує UI, onStart означає видимість, onResume — активну взаємодію. Зміна конфігурації може знищити й створити Activity заново. Процес також може бути завершений системою; onDestroy не є універсально гарантованим місцем збереження важливих даних.
ViewModel переживає звичайну configuration recreation у своїй визначеній області, але не гарантує збереження після смерті процесу. RememberSaveable і SavedStateHandle допомагають відновлювати невеликий потрібний стан. Довгострокові дані зберігають у відповідному сховищі. Кожен механізм має різну тривалість і обмеження розміру.
Lifecycle destination
Навігаційний запис має власний lifecycle та може бути scope для ViewModel. Створення одного ViewModel на всю Activity або окремого для destination має різний наслідок. Якщо потрібний спільний стан двох екранів, явно визначте власника; випадкове отримання двох різних instances створить неузгоджені дані.
Потоки даних збирають із урахуванням lifecycle. На Android collectAsStateWithLifecycle перетворює Flow у Compose State, припиняючи активний збір за відповідних неактивних умов. Це допомагає економити ресурси, але джерело Flow теж повинно мати визначену поведінку. Закриття екрана не завжди означає завершення всіх предметних операцій.
Матриця перевірок
Перевірте список → деталі → назад, повторне натискання, невідомий ID, поворот на деталях і повернення після нього. Для введення в список визначте, чи воно має зберігатися. Для загибелі процесу потрібний окремий сценарій відновлення; просто поворот не перевіряє його. Поясніть, які дані відновлює saved state, а які завантажуються зі сховища.
Типові помилки та практика
Помилки: controller створюється заново при кожному виконанні, у route передається неперевірений текст, невідомий ID спричиняє !!, дані зберігаються лише в Activity полі. Інша проблема — забирати весь стек так, що користувач не може повернутися. Починайте з графа переходів і контракту кожної destination.
Практичний аналіз
Для навчального списку опишіть три destination: список, деталі, редагування. Де живе чернетка редагування? Як уникнути двох джерел істини? Яке повернення потрібне після збереження й скасування? Складіть граф та таблицю перевірок із очікуваним станом.
Життя екрана та відновлення навігації
Back stack зберігає історію переходів у межах навігаційного графа. Перехід до деталей зазвичай додає новий destination, а повернення прибирає верхній запис. Якщо кожне натискання повторно додає ту саму сторінку, користувач може отримати неочікувано довгий шлях назад. Політика повторного переходу повинна відповідати сценарію, наприклад використанню launchSingleTop за потреби.
Передавайте між екранами мінімальний ідентифікатор. Деталі можуть знайти актуальний об’єкт у repository. Великий серіалізований об’єкт у маршруті створює копію стану, яка може застаріти та перевищити зручні межі передачі. Для текстового id також перевіряйте допустимий формат і відсутність об’єкта.
ViewModel зберігає стан у межах свого owner й може пережити зміну конфігурації. Завершення процесу має інші наслідки: SavedStateHandle допомагає відновити потрібні невеликі параметри, а постійне сховище — довготривалі дані. Область ViewModel для окремого destination відрізняється від області спільного графа; обирайте її за тим, які екрани мають ділити стан.
Lifecycle визначає активність компонентів Android. Збір потоку зі спостереженням життєвого циклу дозволяє узгодити роботу UI з видимістю екрана. Але сам факт повернення на екран не визначає, чи треба перезавантажити дані. Задайте правило актуальності: показати кеш, оновити за певним часом або лише за дією користувача. У сценарії повернення перевірте збереження введення, прокрутки та обраного об’єкта окремо.
Схема процесу
Користувач обирає вміст.
Самоперевірка
Як обґрунтувати відповідь своїми словами?
Підсумок
Навігація поєднує маршрути, історію й lifecycle стану. Мінімальні аргументи та явні scopes допомагають уникати неузгоджених копій. Відновлення після конфігурації й процесу потребує різних перевірок.