Jetpack Navigation Compose у 2026: Type-Safe Навігація та Питання на Співбесіді

Комплексний посібник з Jetpack Navigation Compose з type-safe навігацією, розширеними патернами та питаннями для співбесід Android-розробників.

Jetpack Navigation Compose у 2026 році - type-safe навігація в Android

Навігація є одним із фундаментальних елементів кожного мобільного додатку. В екосистемі Android Jetpack Navigation Compose пройшов значну еволюцію, впровадивши у 2026 році повну підтримку type-safe навігації. Цей посібник представляє найновіші підходи до реалізації навігації в додатках Compose та готує до співбесід на позиції Android Developer.

Починаючи з версії Navigation 2.8.0, Kotlin DSL для Compose навігації підтримує передачу аргументів у повністю типізований спосіб, усуваючи потребу в ручному парсингу рядків та значно зменшуючи помилки під час виконання.

Основи Jetpack Navigation Compose

Jetpack Navigation Compose дозволяє декларативно визначати граф навігації безпосередньо в коді Kotlin. На відміну від традиційного підходу на основі XML, весь граф навігації визначається програмно, що забезпечує кращу інтеграцію з Compose та більшу гнучкість.

Базове налаштування вимагає визначення NavHost та окремих призначень:

kotlin
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") {
            HomeScreen(
                onNavigateToDetails = { id ->
                    navController.navigate("details/$id")
                }
            )
        }
        composable(
            route = "details/{itemId}",
            arguments = listOf(
                navArgument("itemId") { type = NavType.StringType }
            )
        ) { backStackEntry ->
            val itemId = backStackEntry.arguments?.getString("itemId")
            DetailsScreen(itemId = itemId)
        }
    }
}

Наведений приклад ілюструє традиційний підхід з аргументами на основі рядків. Хоча він функціональний, він вимагає ручного парсингу та є схильним до друкарських помилок.

Type-Safe Навігація з Kotlin Serialization

Впровадження type-safe навігації усуває проблеми, пов'язані з ручним керуванням аргументами. Завдяки інтеграції з Kotlin Serialization призначення визначаються як класи даних з повною підтримкою типів.

kotlin
@Serializable
object Home

@Serializable
data class Details(val itemId: String)

@Serializable
data class Profile(val userId: Int, val showSettings: Boolean = false)

@Composable
fun TypeSafeNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = Home
    ) {
        composable<Home> {
            HomeScreen(
                onNavigateToDetails = { id ->
                    navController.navigate(Details(itemId = id))
                }
            )
        }
        composable<Details> { backStackEntry ->
            val details: Details = backStackEntry.toRoute()
            DetailsScreen(itemId = details.itemId)
        }
        composable<Profile> { backStackEntry ->
            val profile: Profile = backStackEntry.toRoute()
            ProfileScreen(
                userId = profile.userId,
                showSettings = profile.showSettings
            )
        }
    }
}

Ключові переваги цього підходу включають перевірку типів під час компіляції, автоматичну серіалізацію аргументів та усунення помилок, пов'язаних з неправильними назвами маршрутів.

Вкладені Графи Навігації

У більших додатках організація навігації у вкладені графи покращує читабельність коду та дозволяє модуляризацію функціональності. Кожен модуль додатку може визначати власний підграф навігації.

kotlin
@Serializable
object AuthGraph

@Serializable
object Login

@Serializable
object Register

@Serializable
object ForgotPassword

fun NavGraphBuilder.authNavGraph(navController: NavController) {
    navigation<AuthGraph>(startDestination = Login) {
        composable<Login> {
            LoginScreen(
                onNavigateToRegister = {
                    navController.navigate(Register)
                },
                onNavigateToForgotPassword = {
                    navController.navigate(ForgotPassword)
                }
            )
        }
        composable<Register> {
            RegisterScreen(
                onRegistrationComplete = {
                    navController.popBackStack(Login, inclusive = true)
                    navController.navigate(Home)
                }
            )
        }
        composable<ForgotPassword> {
            ForgotPasswordScreen(
                onPasswordReset = {
                    navController.popBackStack()
                }
            )
        }
    }
}

Вкладені графи забезпечують інкапсуляцію логіки навігації, специфічної для даного модуля, що особливо корисно в багатомодульній архітектурі.

Deep links дозволяють безпосередньо відкрити конкретний екран додатку із зовнішнього джерела. Navigation Compose підтримує deep links через декларативну конфігурацію.

kotlin
@Serializable
data class Product(
    val productId: String,
    val source: String? = null
)

NavHost(
    navController = navController,
    startDestination = Home
) {
    composable<Product>(
        deepLinks = listOf(
            navDeepLink<Product>(
                basePath = "https://example.com/product"
            )
        )
    ) { backStackEntry ->
        val product: Product = backStackEntry.toRoute()
        ProductScreen(
            productId = product.productId,
            source = product.source
        )
    }
}

Конфігурація в AndroidManifest.xml залишається необхідною для підтримки deep links на рівні системи:

xml
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="example.com"
            android:pathPrefix="/product" />
    </intent-filter>
</activity>

Керування Станом Навігації

Ефективне керування станом навігації вимагає розуміння життєвого циклу NavBackStackEntry та механізмів збереження стану. SavedStateHandle дозволяє зберігати дані, що переживають реконфігурацію.

kotlin
@HiltViewModel
class ProductViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    
    private val productRoute: Product = savedStateHandle.toRoute()
    
    val productId: String = productRoute.productId
    
    private val _uiState = MutableStateFlow(ProductUiState())
    val uiState: StateFlow<ProductUiState> = _uiState.asStateFlow()
    
    init {
        loadProduct(productId)
    }
    
    private fun loadProduct(id: String) {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true) }
            // Fetch product data
        }
    }
}

Інтеграція з Hilt забезпечує автоматичне впровадження SavedStateHandle у ViewModel, що дозволяє type-safe доступ до аргументів навігації.

Анімації Переходів

Navigation Compose пропонує підтримку для налаштовуваних анімацій переходів між екранами. Анімації визначаються на рівні окремих призначень або глобально для всього NavHost.

kotlin
NavHost(
    navController = navController,
    startDestination = Home,
    enterTransition = {
        slideIntoContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.Start,
            animationSpec = tween(300)
        )
    },
    exitTransition = {
        slideOutOfContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.Start,
            animationSpec = tween(300)
        )
    },
    popEnterTransition = {
        slideIntoContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.End,
            animationSpec = tween(300)
        )
    },
    popExitTransition = {
        slideOutOfContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.End,
            animationSpec = tween(300)
        )
    }
) {
    // Destinations
}

Умовна Навігація та Guard'и

Реалізація умовної навігації, наприклад перевірка стану авторизації перед доступом до захищених екранів, вимагає відповідної архітектури.

kotlin
@Composable
fun AppNavigation(
    isAuthenticated: Boolean,
    onAuthRequired: () -> Unit
) {
    val navController = rememberNavController()
    
    LaunchedEffect(isAuthenticated) {
        if (!isAuthenticated) {
            navController.navigate(Login) {
                popUpTo(navController.graph.startDestinationId) {
                    inclusive = true
                }
            }
        }
    }
    
    NavHost(
        navController = navController,
        startDestination = if (isAuthenticated) Home else Login
    ) {
        composable<Home> {
            HomeScreen()
        }
        composable<Login> {
            LoginScreen(
                onLoginSuccess = {
                    navController.navigate(Home) {
                        popUpTo(Login) { inclusive = true }
                    }
                }
            )
        }
    }
}

Тестування Навігації

Тестування навігації в додатках Compose вимагає належної підготовки тестового середовища. Бібліотека navigation-testing надає інструменти для верифікації поведінки навігації.

kotlin
class NavigationTest {
    
    @get:Rule
    val composeTestRule = createComposeRule()
    
    private lateinit var navController: TestNavHostController
    
    @Before
    fun setup() {
        composeTestRule.setContent {
            navController = TestNavHostController(LocalContext.current)
            navController.navigatorProvider.addNavigator(
                ComposeNavigator()
            )
            AppNavigation(navController = navController)
        }
    }
    
    @Test
    fun navigateToDetails_displaysCorrectScreen() {
        composeTestRule.onNodeWithText("View Details").performClick()
        
        val currentRoute = navController.currentBackStackEntry?.toRoute<Details>()
        assertNotNull(currentRoute)
        assertEquals("expected-id", currentRoute?.itemId)
    }
}

Готовий до співбесід з Android?

Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.

Питання на Співбесіді: Jetpack Navigation Compose

Нижче представлено типові питання, які задають під час співбесід на позиції Android Developer щодо навігації в Compose.

Питання: Які основні відмінності між навігацією на основі рядків та type-safe навігацією в Compose?

Навігація на основі рядків вимагає ручного визначення маршрутів як рядків та парсингу аргументів з NavBackStackEntry. Вона схильна до друкарських помилок та не пропонує перевірки типів під час компіляції. Type-safe навігація використовує класи даних з анотацією @Serializable як призначення, забезпечуючи повну перевірку типів, автоматичну серіалізацію та десеріалізацію аргументів, а також усунення помилок, пов'язаних з неправильними назвами маршрутів.

Питання: Як реалізувати умовну навігацію на основі стану авторизації?

Умовна навігація реалізується через спостереження за станом авторизації в LaunchedEffect або з використанням derivedStateOf. Коли стан авторизації змінюється, navController програмно навігує до відповідного призначення, використовуючи popUpTo з inclusive = true для очищення стеку навігації.

Питання: Поясніть різницю між popBackStack() та navigateUp().

Метод popBackStack() безумовно видаляє поточне призначення зі стеку навігації. Метод navigateUp() поважає структуру навігації, визначену deep links та батьківськими графами, потенційно навігуючи до призначення поза поточним графом, якщо додаток було запущено через deep link.

Питання: Як зберегти стан екрана під час навігації в Compose?

Стан екрана зберігається за допомогою rememberSaveable для простих значень, SavedStateHandle у ViewModel для складних даних та правильної конфігурації NavHost з належним керуванням NavBackStackEntry. Додатково можна використовувати механізм saveState та restoreState в NavOptions.

Питання: Які найкращі практики організації навігації в багатомодульному додатку?

У багатомодульній архітектурі кожен функціональний модуль визначає власні призначення як публічні класи даних та функцію розширення NavGraphBuilder, що додає підграф навігації. Модуль app агрегує всі підграфи в головному NavHost. Призначення експонуються через публічний API модуля, тоді як реалізація екранів залишається приватною.

Висновок

Jetpack Navigation Compose у 2026 році пропонує зрілий та комплексний набір інструментів для реалізації навігації в Android-додатках. Впровадження type-safe навігації значно підвищує безпеку типів та зменшує помилки під час виконання. Розуміння розширених патернів, таких як вкладені графи, deep links чи анімації переходів, становить ключовий елемент підготовки до співбесід на позиції Android Developer.

Регулярна практика реалізації різних навігаційних сценаріїв та глибоке розуміння внутрішніх механізмів бібліотеки Navigation Compose готує до ефективного вирішення проблем як у щоденній роботі, так і під час технічних співбесід.

Щоденний виклик

Чи знайдеш ти помилку в Android?

Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Anthony Fillion-Maillet

Автор:

Anthony Fillion-Maillet

Засновник SharpSkill

Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.

Оновлено 1 вересня 2026 р.

Теги

#android
#jetpack compose
#navigation
#kotlin
#type-safe

Поділитися

Пов'язані статті