# Jetpack Navigation Compose 2026: Navigasi Type-Safe dan Pertanyaan Interview > Pelajari Jetpack Navigation Compose 2.10 dengan navigasi type-safe menggunakan Kotlin Serialization. Panduan lengkap dengan contoh kode dan pertanyaan interview Android. - Published: 2026-09-01 - Updated: 2026-09-01 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Jetpack Navigation Compose 2.10 menghadirkan keamanan tipe waktu kompilasi untuk navigasi Android melalui Kotlin Serialization. Pendekatan ini menghilangkan crash runtime akibat ketidakcocokan argumen dan menyederhanakan refactoring di seluruh codebase yang besar. > **Navigation 2.10 Stabil** > > Navigation Compose 2.10.0, dirilis Agustus 2026, memerlukan minimum SDK 24. Route type-safe menggunakan data class `@Serializable` sebagai pengganti destinasi berbasis string, sehingga menangkap error navigasi pada waktu kompilasi. ## Menyiapkan Navigasi Type-Safe di Navigation 2.10 API navigasi type-safe memerlukan Kotlin Serialization. Tambahkan dependensi berikut ke `build.gradle.kts` level modul: ```kotlin // build.gradle.kts plugins { id("org.jetbrains.kotlin.plugin.serialization") version "2.1.0" } dependencies { implementation("androidx.navigation:navigation-compose:2.10.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") } ``` Definisikan destinasi sebagai tipe serializable. Gunakan `object` untuk layar tanpa argumen dan `data class` untuk layar yang menerima parameter: ```kotlin // Routes.kt import kotlinx.serialization.Serializable @Serializable object Home @Serializable object ProductList @Serializable data class ProductDetail(val productId: String) @Serializable data class Checkout(val cartId: String, val promoCode: String? = null) ``` Kompiler memastikan bahwa semua class route dianotasi dengan `@Serializable`. Anotasi yang hilang memicu error lint di Navigation 2.9+. ## Membangun NavHost dengan Route Serializable Composable `NavHost` menerima tipe serializable secara langsung. Setiap blok `composable` menangani tipe destinasi tertentu: ```kotlin // AppNavigation.kt @Composable fun AppNavigation( navController: NavHostController = rememberNavController() ) { NavHost( navController = navController, startDestination = Home ) { composable { HomeScreen( onNavigateToProducts = { navController.navigate(ProductList) } ) } composable { ProductListScreen( onProductClick = { productId -> navController.navigate(ProductDetail(productId)) } ) } composable { backStackEntry -> // Ekstrak route bertipe dari back stack entry val route: ProductDetail = backStackEntry.toRoute() ProductDetailScreen( productId = route.productId, onCheckout = { cartId -> navController.navigate(Checkout(cartId)) } ) } composable { backStackEntry -> val route: Checkout = backStackEntry.toRoute() CheckoutScreen( cartId = route.cartId, promoCode = route.promoCode ) } } } ``` Extension `toRoute()` mengembalikan instance destinasi yang sepenuhnya bertipe. Mengganti nama properti di data class secara otomatis memperbarui semua penggunaan melalui refactoring IDE. ## Nested Navigation Graph untuk Modul Fitur Aplikasi besar mendapat manfaat dari nested navigation graph. Setiap modul fitur mendefinisikan graph-nya sendiri, dan root graph menyusunnya: ```kotlin // AuthNavigation.kt @Serializable object AuthGraph // Identifier graph @Serializable object Login @Serializable object Register @Serializable data class PasswordReset(val email: String) fun NavGraphBuilder.authNavGraph(navController: NavHostController) { navigation(startDestination = Login) { composable { LoginScreen( onRegisterClick = { navController.navigate(Register) }, onForgotPassword = { email -> navController.navigate(PasswordReset(email)) }, onLoginSuccess = { navController.navigate(Home) { popUpTo { inclusive = true } } } ) } composable { RegisterScreen( onRegistrationComplete = { navController.navigate(Home) { popUpTo { inclusive = true } } } ) } composable { backStackEntry -> val route: PasswordReset = backStackEntry.toRoute() PasswordResetScreen(email = route.email) } } } ``` `popUpTo` dengan `inclusive = true` menghapus seluruh alur auth dari back stack setelah login berhasil, mencegah pengguna kembali ke layar login. ## Value Class sebagai Argumen Route Navigation 2.9.0-alpha03 menambahkan dukungan untuk [value class](https://kotlinlang.org/docs/inline-classes.html) dalam route. Pola ini memaksakan keamanan tipe untuk ID dan mencegah tercampurnya parameter dengan tipe primitif yang sama: ```kotlin // Domain.kt @JvmInline @Serializable value class ProductId(val value: String) @JvmInline @Serializable value class UserId(val value: String) @Serializable data class ProductDetail(val productId: ProductId) @Serializable data class UserProfile(val userId: UserId) ``` Sekarang kompiler mencegah pengiriman `UserId` di tempat yang mengharapkan `ProductId`, bug umum dalam navigasi berbasis string. ## Deep Link dengan Route Type-Safe Deep link memetakan URI eksternal ke route serializable. Definisikan pola di blok `composable`: ```kotlin // AppNavigation.kt composable( deepLinks = listOf( navDeepLink { uriPattern = "https://example.com/products/{productId}" } ) ) { backStackEntry -> val route: ProductDetail = backStackEntry.toRoute() ProductDetailScreen(productId = route.productId) } ``` Placeholder `{productId}` dipetakan langsung ke properti `productId` di data class `ProductDetail`. Navigation mengekstrak dan mendeserialize argumen secara otomatis. Daftarkan deep link di `AndroidManifest.xml`: ```xml ``` ## Predictive Back Gesture dengan Navigation Compose Android 14+ mendukung predictive back gesture di mana pengguna melihat pratinjau layar sebelumnya sebelum menyelesaikan aksi. Navigation Compose 2.10 terintegrasi dengan fitur ini melalui `SeekableTransitionState`: ```kotlin // AppNavigation.kt NavHost( navController = navController, startDestination = Home, enterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Start) }, exitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Start) }, popEnterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.End) }, popExitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.End) } ) { // destinasi } ``` Predictive back gesture menampilkan destinasi sebelumnya secara real-time saat pengguna melakukan swipe. Melepaskan gesture sebelum threshold membatalkan navigasi dan kembali ke layar saat ini. ## Pertanyaan Interview Umum tentang Navigation Compose Interview Android senior sering menggali keputusan arsitektur navigasi. Berikut adalah pertanyaan yang membedakan kandidat berpengalaman. ### Mengapa menggunakan navigasi type-safe daripada route berbasis string? Route berbasis string seperti `"product/{productId}"` menyebabkan crash runtime ketika argumen salah eja atau memiliki tipe yang salah. Route type-safe menangkap error ini pada waktu kompilasi. Refactoring parameter route memperbarui semua penggunaan melalui tooling IDE, sedangkan route berbasis string memerlukan find-and-replace manual di seluruh codebase. ### Bagaimana cara berbagi data antar destinasi tanpa mengirim objek besar? > **Hindari Argumen Route Besar** > > Route diserialize ke dalam saved instance state. Mengirim objek besar seperti katalog produk berisiko `TransactionTooLargeException`. Kirim ID dan muat data dari repository atau shared ViewModel sebagai gantinya. Pola untuk berbagi data melibatkan scoped ViewModel: ```kotlin // ProductViewModel.kt @HiltViewModel class ProductViewModel @Inject constructor( private val repository: ProductRepository, savedStateHandle: SavedStateHandle ) : ViewModel() { // Ekstrak route bertipe dari SavedStateHandle private val productId: String = savedStateHandle.toRoute().productId val product = repository.getProduct(productId) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) } ``` ### Bagaimana cara menguji navigasi di Compose? Pengujian navigasi memverifikasi bahwa aksi pengguna memicu perubahan destinasi yang benar: ```kotlin // NavigationTest.kt class NavigationTest { @get:Rule val composeTestRule = createComposeRule() @Test fun clickingProduct_navigatesToDetail() { val navController = TestNavHostController(ApplicationProvider.getApplicationContext()) navController.navigatorProvider.addNavigator(ComposeNavigator()) composeTestRule.setContent { AppNavigation(navController = navController) } // Navigasi ke daftar produk composeTestRule.onNodeWithText("View Products").performClick() // Klik produk pertama composeTestRule.onNodeWithTag("product_item_0").performClick() // Verifikasi destinasi saat ini val currentRoute = navController.currentBackStackEntry?.toRoute() assertThat(currentRoute).isNotNull() } } ``` ### Apa yang terjadi ketika NavController digunakan setelah dihancurkan? Navigation 2.9.0-alpha01 mengubah perilaku ini. Menggunakan `NavController` setelah `Activity` atau `Fragment` yang menghostingnya dihancurkan sekarang melempar `IllegalStateException`. Versi sebelumnya gagal secara diam-diam atau menghasilkan perilaku yang tidak terdefinisi. Perubahan ini memunculkan bug lifecycle lebih awal dalam pengembangan. ### Bagaimana cara menangani navigasi kondisional berdasarkan status auth? Pola umum mengamati status auth dan mengarahkan sesuai: ```kotlin // MainScreen.kt @Composable fun MainScreen( authState: AuthState, navController: NavHostController = rememberNavController() ) { LaunchedEffect(authState) { when (authState) { is AuthState.Authenticated -> { navController.navigate(Home) { popUpTo(0) { inclusive = true } } } is AuthState.Unauthenticated -> { navController.navigate(AuthGraph) { popUpTo(0) { inclusive = true } } } else -> { /* loading, tidak melakukan apa-apa */ } } } NavHost( navController = navController, startDestination = if (authState is AuthState.Authenticated) Home else AuthGraph ) { authNavGraph(navController) composable { HomeScreen() } } } ``` `LaunchedEffect` bereaksi terhadap perubahan status auth dan menghapus seluruh back stack dengan `popUpTo(0) { inclusive = true }` untuk mencegah navigasi kembali ke alur yang salah. ## Migrasi dari Route String ke Navigasi Type-Safe Proyek yang sudah ada dapat bermigrasi secara bertahap. Route string dan route type-safe dapat berdampingan dalam `NavHost` yang sama: ```kotlin // AppNavigation.kt NavHost( navController = navController, startDestination = "home" // Route string legacy ) { // Destinasi berbasis string legacy composable("home") { HomeScreen(onNavigateToProduct = { id -> navController.navigate(ProductDetail(id)) // Navigasi type-safe baru }) } // Destinasi type-safe baru composable { backStackEntry -> val route: ProductDetail = backStackEntry.toRoute() ProductDetailScreen(productId = route.productId) } } ``` Pendekatan ini memungkinkan migrasi satu layar pada satu waktu tanpa menulis ulang seluruh navigation graph. ## Poin Penting Jetpack Navigation Compose di 2026 - Navigation 2.10.0 adalah versi stabil saat ini dengan minimum SDK 24 - Route type-safe menggunakan data class `@Serializable` sebagai pengganti destinasi string - Value class memberikan keamanan tipe tambahan untuk ID dan mencegah tercampurnya parameter - Nested navigation graph mengorganisir modul fitur dengan back stack independen - Deep link memetakan pola URI langsung ke properti route - Predictive back gesture terintegrasi secara otomatis dengan transisi standar - Argumen route harus tetap ringan: kirim ID, muat data dari repository - Migrasi dari route string dapat dilakukan secara bertahap dengan navigation graph campuran - [Persiapan interview Android](/technologies/android) membahas pola-pola ini secara mendalam - Lihat juga [pertanyaan interview Jetpack Compose](/blog/android/jetpack-compose-interview-questions) untuk konsep UI terkait --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/android/jetpack-navigation-compose-type-safe-2026