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.

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 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:
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:
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<T> menangani tipe destinasi tertentu:
@Composable
fun AppNavigation(
navController: NavHostController = rememberNavController()
) {
NavHost(
navController = navController,
startDestination = Home
) {
composable<Home> {
HomeScreen(
onNavigateToProducts = { navController.navigate(ProductList) }
)
}
composable<ProductList> {
ProductListScreen(
onProductClick = { productId ->
navController.navigate(ProductDetail(productId))
}
)
}
composable<ProductDetail> { backStackEntry ->
// Ekstrak route bertipe dari back stack entry
val route: ProductDetail = backStackEntry.toRoute()
ProductDetailScreen(
productId = route.productId,
onCheckout = { cartId ->
navController.navigate(Checkout(cartId))
}
)
}
composable<Checkout> { backStackEntry ->
val route: Checkout = backStackEntry.toRoute()
CheckoutScreen(
cartId = route.cartId,
promoCode = route.promoCode
)
}
}
}Extension toRoute<T>() 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:
@Serializable
object AuthGraph // Identifier graph
@Serializable
object Login
@Serializable
object Register
@Serializable
data class PasswordReset(val email: String)
fun NavGraphBuilder.authNavGraph(navController: NavHostController) {
navigation<AuthGraph>(startDestination = Login) {
composable<Login> {
LoginScreen(
onRegisterClick = { navController.navigate(Register) },
onForgotPassword = { email ->
navController.navigate(PasswordReset(email))
},
onLoginSuccess = {
navController.navigate(Home) {
popUpTo<AuthGraph> { inclusive = true }
}
}
)
}
composable<Register> {
RegisterScreen(
onRegistrationComplete = {
navController.navigate(Home) {
popUpTo<AuthGraph> { inclusive = true }
}
}
)
}
composable<PasswordReset> { backStackEntry ->
val route: PasswordReset = backStackEntry.toRoute()
PasswordResetScreen(email = route.email)
}
}
}popUpTo<AuthGraph> dengan inclusive = true menghapus seluruh alur auth dari back stack setelah login berhasil, mencegah pengguna kembali ke layar login.
Siap menguasai wawancara Android Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Value Class sebagai Argumen Route
Navigation 2.9.0-alpha03 menambahkan dukungan untuk value class dalam route. Pola ini memaksakan keamanan tipe untuk ID dan mencegah tercampurnya parameter dengan tipe primitif yang sama:
@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:
composable<ProductDetail>(
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:
<!-- AndroidManifest.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="/products" />
</intent-filter>
</activity>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:
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?
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:
@HiltViewModel
class ProductViewModel @Inject constructor(
private val repository: ProductRepository,
savedStateHandle: SavedStateHandle
) : ViewModel() {
// Ekstrak route bertipe dari SavedStateHandle
private val productId: String = savedStateHandle.toRoute<ProductDetail>().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:
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<ProductDetail>()
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:
@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<Home> { 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.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
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:
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<ProductDetail> { 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
@Serializablesebagai 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 membahas pola-pola ini secara mendalam
- Lihat juga pertanyaan interview Jetpack Compose untuk konsep UI terkait
Bisakah kamu menemukan bug di Android?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 1 September 2026
Bagikan
Artikel terkait

Modularisasi Android 2026: Arsitektur Multi-Modul dan Pertanyaan Interview
Kuasai arsitektur multi-modul Android dengan convention plugins, Gradle version catalogs, dan feature modules. Termasuk pertanyaan interview umum tentang strategi modularisasi.

Android CameraX 2026: Panduan Lengkap Pengambilan Foto dan Video dengan Pertanyaan Wawancara
Pelajari CameraX di Android 2026: pengambilan foto, perekaman video, integrasi Jetpack Compose, dan pertanyaan wawancara teknis untuk developer Android.

Android WorkManager 2026: Panduan Lengkap Background Tasks, Constraints, dan Pertanyaan Interview
Pelajari Android WorkManager untuk menjalankan background tasks dengan constraints, chaining, dan CoroutineWorker. Termasuk pertanyaan interview untuk persiapan wawancara kerja Android developer.