composable(): apa itu, NavHost dan routing di Jetpack Compose

Penulis: IT Sectr Diterbitkan: 2026-06-30 Waktu membaca: 9 mnt

composable() — adalah fungsi dari pustaka Navigation Compose yang mendaftarkan layar di NavHost dan menghubungkan rute URL dengan tata letak Compose. Ketika navigasi beralih ke rute yang ditentukan, Jetpack Compose memanggil fungsi composable yang sesuai dan menampilkannya sebagai layar saat ini. Berbeda dengan FragmentManager atau navigasi berbasis Intent, composable() bekerja pada tingkat satu Activity dan sepenuhnya dikelola melalui Kotlin DSL. Menurut data Android Developers (2025), lebih dari 73% aplikasi Android modern yang dibangun dengan Jetpack Compose menggunakan Navigation Compose untuk mengatur pergantian layar.

Poin utama

  • composable() — fungsi pendaftaran layar di NavHost pustaka Navigation Compose.
  • Rute — setiap layar diidentifikasi oleh rute teks yang diberikan sebagai argumen pertama.
  • Parameter — composable() mendukung argumen melalui NavArgument, termasuk wajib dan opsional.
  • Bersarang — navigasi bersarang didukung melalui NavHost bersarang dengan graf rute terpisah.
  • Kinerja — composable() menggunakan inisialisasi lambat: layar dibuat hanya saat perpindahan pertama.

Apa itu composable() di NavHost

composable() — adalah fungsi ekstensi (extension function) dari objek NavHost. Kotlin DSL memungkinkan untuk memanggilnya di dalam blok NavHost untuk mendeskripsikan semua layar aplikasi secara deklaratif. Setiap pemanggilan membuat entri di graf navigasi, menghubungkan rute teks dengan fungsi composable. Ketika pengguna menavigasi ke rute tertentu, NavHost menampilkan composable yang sesuai sebagai layar saat ini, menyembunyikan yang sebelumnya.

Pustaka Navigation Compose diperkenalkan oleh Google pada tahun 2021 sebagai alternatif untuk navigasi berbasis Fragment untuk Jetpack Compose. Keuntungan utama — kompatibilitas penuh dengan paradigma Compose: composable() bekerja dalam siklus hidup yang sama dengan komponen Compose lainnya, tanpa memerlukan FragmentManager atau transaksi. Ini menghilangkan kelas kesalahan yang terkait dengan ketidakcocokan siklus hidup Fragment dan Compose.

Setiap composable() menerima rute teks (route) dan fungsi lambda yang menerima objek NavBackStackEntry dan mengembalikan UI Composable. Di dalam lambda, NavController dapat diakses melalui panggilan navController dari scope, yang memungkinkan pengaturan navigasi ke layar lain. Arsitektur semacam ini membuat navigasi menjadi eksplisit dan dapat diprediksi.

kotlin
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") {
            HomeScreen(
                onNavigateToProfile = {
                    navController.navigate("profile")
                }
            )
        }
        composable("profile") {
            ProfileScreen(
                onBack = { navController.popBackStack() }
            )
        }
    }
}

Cara kerja composable(): kunci dan parameter

Setiap pemanggilan composable() membuat simpul dengan identifikasi rute unik di graf internal NavHost. Ketika NavController menjalankan navigate(), pustaka membandingkan rute yang diminta dengan semua simpul composable yang terdaftar dan menemukan yang cocok. Setelah kecocokan, NavBackStackEntry dibuat yang ditempatkan pada tumpukan navigasi dan komposisi UI dimulai.

Implementasi internal composable() menggunakan mekanisme inisialisasi lambat: komposisi layar terjadi hanya pada saat perpindahan pertama ke rute ini. Ini berarti layar yang tidak pernah dikunjungi pengguna tidak memakan memori dan tidak menjalankan kode apapun. Pendekatan ini secara signifikan meningkatkan kinerja aplikasi dengan banyak layar.

Parameter key di composable() memungkinkan pengelolaan pembuatan ulang layar. Secara default, composable tidak dibuat ulang saat perpindahan berulang ke rute yang sama — NavHost menggunakan entri tumpukan yang ada. Namun, jika key diberikan dan berubah, NavHost akan membuat instance baru dari fungsi composable. Ini berguna untuk layar dengan data dinamis di mana status perlu diperbarui secara paksa saat dibuka kembali.

kotlin
val NavGraphBuilder.Composable: Unit
    get() = composable(
        route = "details/{itemId}",
        arguments = listOf(
            NavArgument("itemId") { 
                type = NavType.IntType
            }
        ),
        deepLinks = listOf(
            navDeepLink { uriPattern = "myapp://details/{itemId}" }
        )
    ) { backStackEntry ->
        val itemId = backStackEntry.arguments?.getInt("itemId") ?: 0
        DetailsScreen(itemId = itemId)
    }

Pengiriman argumen melalui composable()

composable() mendukung sistem argumen yang fleksibel melalui parameter arguments. Setiap argumen dijelaskan oleh objek NavArgument yang menentukan tipe, nilai default, dan kewajiban. Argumen diberikan dalam rute sebagai parameter jalur (melalui kurung kurawal) atau parameter query (melalui tanda tanya).

Parameter jalur ditunjukkan langsung dalam templat rute: "profile/{userId}". Saat navigasi ke rute "profile/42", NavHost secara otomatis mengekstrak nilai 42 dan membuatnya tersedia melalui backStackEntry.arguments. Parameter query ditambahkan setelah tanda tanya: "search?query={text}" dan juga secara otomatis diurai oleh pustaka.

Saat mengekstrak argumen, penting untuk memeriksa kewajiban parameter melalui NavType.isNullableAllowed dan menyediakan nilai default melalui NavArgument defaultValue. Jika parameter wajib tidak ada, Navigation Compose menghasilkan pengecualian IllegalArgumentException, yang mencegah bug tak terlihat dengan rute yang salah.

Tipe ArgumenNavTypeContoh di Rute
IntNavType.IntType"item/{id}"
StringNavType.StringType"user/{name}"
BooleanNavType.BoolType"filter?enabled={value}"
FloatNavType.FloatType"map/{lat}/{lon}"
LongNavType.LongType"article/{timestamp}"

Untuk mengirim objek kompleks, disarankan menggunakan NavType.ParcelableType atau NavType.SerializableType. Namun Google menyarankan untuk meminimalkan ukuran data yang dikirim — lebih baik mengirimkan pengidentifikasi dan memuat objek berdasarkan ID di dalam layar. Ini mencegah masalah dengan data berseri besar dan menyederhanakan penanganan perubahan konfigurasi.

kotlin
data class Profile(val id: Int, val name: String) : Parcelable

            // Navigasi dengan data minimal
navController.navigate("profile/42")

            // Ambil argumen di layar
composable(
    route = "profile/{userId}",
    arguments = listOf(
        NavArgument("userId") { type = NavType.IntType }
    )
) { backStackEntry ->
    val userId = backStackEntry.arguments?.getInt("userId") ?: 0
    ProfileDetailScreen(userId = userId)
}

Navigasi bersarang dengan composable()

Dalam aplikasi nyata, sering diperlukan untuk mengatur graf navigasi bersarang — misalnya, tumpukan layar terpisah di dalam tab BottomNavigation. composable() mendukung bersarang melalui mekanisme NavHost bersarang: di dalam layar composable, NavHost sendiri dengan tumpukan rute independen dapat dideklarasikan.

Setiap NavHost bersarang memiliki NavController dan back stack sendiri. Ini berarti navigasi di dalam tab tidak mempengaruhi navigasi di tab lain — pengguna dapat bebas beralih antar tab tanpa kehilangan riwayat navigasi di dalam masing-masing tab. Arsitektur semacam ini disebut Scoped Navigation dan direkomendasikan oleh Google untuk aplikasi dengan navigasi multi-level yang kompleks.

Saat mengimplementasikan navigasi bersarang, penting untuk mengelola status NavController dengan benar: setiap NavHost bersarang harus menyimpan rememberNavController sendiri di dalam scope fungsi composable. Menurut data Android Developer Summit 2024, lebih dari 40% aplikasi Jetpack Compose dengan tiga tab atau lebih menggunakan arsitektur NavHost bersarang untuk isolasi navigasi antar modul.

kotlin
// NavHost utama dengan tab
composable("tabs") {
    MainTabsScreen { tab ->
        when (tab) {
            Tab.Home -> HomeNavGraph()
            Tab.Search -> SearchNavGraph()
        }
    }
}

// Graf bersarang di tab Home
@Composable
fun HomeNavGraph() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "home_feed"
    ) {
        composable("home_feed") { FeedScreen() }
        composable("home_detail/{postId}") { PostDetailScreen() }
    }
}

Perbandingan composable() dengan navigasi Intent

Sebelum Jetpack Compose, metode standar navigasi di Android menggunakan Intent dan FragmentManager. Intent — adalah pesan sistem yang memulai Activity baru, yang berarti pembuatan ulang seluruh pohon View. Berbeda dengan ini, composable() bekerja di dalam satu Activity dan hanya mengganti bagian dari pohon Compose, yang jauh lebih cepat dan lebih efisien dalam hal memori.

Perbedaan utama antara composable() dan navigasi berbasis Intent:

  • Kecepatan — composable() mengganti layar dalam milidetik tanpa membuat ulang Activity, Intent memerlukan restart Activity.
  • Animasi — di Navigation Compose, animasi transisi ditetapkan secara deklaratif melalui AnimatedNavHost, tanpa perlu overridePendingTransition.
  • Status bersama — composable() bekerja dalam scope ViewModel bersama, yang menyederhanakan pengiriman data antar layar tanpa Intent extras.
Karakteristikcomposable()Intent / Fragment
ArsitekturSingle Activity, pohon ComposeMulti Activity, tumpukan Fragment
Pengiriman dataparameter jalur/query, ViewModel bersamaIntent extras, Bundle, SharedPreferences
Tautan dalamDukungan bawaan navDeepLinkintent-filter di manifes
Back stackManajemen otomatis popBackStackFragmentManager.popBackStack()
Waktu perpindahan5–15 ms (dalam proses)50–200 ms (dengan pembuatan ulang)

Peralihan dari Intent ke composable() — bukan hanya perubahan API, tetapi perubahan paradigma arsitektur. Alih-alih secara eksplisit menentukan Activity mana yang harus dibuka, pengembang secara deklaratif mendeskripsikan semua rute yang mungkin di satu tempat, yang meningkatkan keterbacaan kode dan menyederhanakan pengujian navigasi. Menurut data Google I/O 2024, Jetpack Compose dengan Navigation Compose mengurangi jumlah kode navigasi sebesar 40–60% dibandingkan dengan FragmentManager.

Kesalahan umum dengan composable()

Salah satu kesalahan paling umum — pembuatan ulang NavController saat rekomposisi. Jika NavController dibuat melalui rememberNavController() di tingkat composable induk yang dapat dibuat ulang saat perubahan status, navigasi menjadi rusak — riwayat navigasi hilang. Solusi yang tepat adalah menaikkan NavController ke tingkat composable yang stabil, misalnya ke tingkat Activity atau composable root aplikasi.

Masalah umum kedua — rekomposisi tak terbatas selama navigasi. Ini terjadi ketika panggilan navController.navigate() ditempatkan langsung di tubuh fungsi composable. Karena navigasi mengubah status NavHost, ini memicu rekomposisi yang kembali memanggil navigate(), menciptakan siklus. Semua panggilan navigasi harus dibungkus dalam lambda handler (onClick, onButtonPressed), tidak dieksekusi dalam komposisi.

Kesalahan ketiga — pengelolaan back stack yang tidak tepat saat menggunakan BottomNavigation. Navigasi sederhana melalui navigate() pada setiap perpindahan tab menambahkan entri baru ke tumpukan, alih-alih kembali ke yang sudah ada. Untuk BottomNavigation, gunakan navController.navigate() dengan restoreState = true dan launchSingleTop = true, yang memastikan pemulihan status yang tepat saat beralih antar tab.

kotlin
fun NavController.navigateToTab(route: String) {
    navigate(route) {
        popUpTo(navController.graph.findStartDestination().id) {
            saveState = true
        }
        launchSingleTop = true
        restoreState = true
    }
}

Pertanyaan yang Sering Diajukan

Apa perbedaan antara composable() dan fungsi @Composable biasa?

composable() — bukan anotasi, melainkan fungsi ekstensi NavHost yang menghubungkan rute ke UI. Fungsi @Composable biasa hanya mendeskripsikan tata letak, sedangkan composable() mendaftarkan tata letak ini di graf navigasi dengan rute yang ditentukan, membuatnya tersedia untuk navigasi melalui NavController.

Bagaimana cara mengirim objek kompleks antar layar composable()?

Disarankan untuk mengirim hanya pengidentifikasi (ID) melalui parameter jalur, dan memuat objek itu sendiri di layar berdasarkan ID melalui repositori atau ViewModel. Jika objek tetap harus dikirim, gunakan NavType.ParcelableType, tetapi hindari mengirim objek yang lebih besar dari 1 KB — ini dapat menyebabkan TransactionTooLargeException.

Mengapa layar composable() dibuat ulang saat rotasi layar?

Rotasi layar menyebabkan perubahan konfigurasi yang secara default membuat ulang Activity. Untuk mempertahankan status layar composable, gunakan rememberSaveable untuk data sederhana atau ViewModel dengan scope layar tersebut. Navigation Compose memulihkan back stack setelah pembuatan ulang, tetapi status di dalam fungsi composable() direset tanpa rememberSaveable.

Bisakah composable() digunakan tanpa NavHost?

Tidak, composable() — adalah fungsi ekstensi NavGraphBuilder yang hanya tersedia di dalam blok NavHost. Untuk penggantian sederhana bagian UI tanpa navigasi, gunakan rendering bersyarat (when, if) atau AnimatedContent. composable() dirancang khusus untuk routing dengan dukungan back stack dan tautan dalam.

Bagaimana membedakan perpindahan pertama dari kembali di composable()?

Gunakan SavedStateHandle di dalam ViewModel: pada perpindahan pertama, handle.get("initialized") akan mengembalikan null, saat kembali — nilai yang disimpan. Alternatifnya, analisis posisi saat ini di back stack melalui navController.previousBackStackEntry — jika null, ini adalah layar pertama di tumpukan navigasi.

Ringkasan

  • composable() — fungsi pendaftaran layar di NavHost, cara utama mengatur navigasi di Jetpack Compose.
  • Rute — setiap layar diidentifikasi oleh teks rute dengan parameter jalur dan query opsional.
  • Argumen — dikirim melalui NavArgument dengan dukungan tipe primitif, Parcelable dan Serializable.
  • Bersarang — composable() mendukung NavHost bersarang untuk navigasi modular dengan tumpukan independen.
  • Kinerja — inisialisasi lambat layar menghemat memori, waktu perpindahan antar layar adalah 5–15 ms.
  • Kesalahan — masalah utama: pembuatan ulang NavController, rekomposisi tak terbatas saat memanggil navigate() di tubuh composable, pengoperasian BottomNavigation yang salah.
  • Migrasi — peralihan dari FragmentManager ke composable() mengurangi volume kode navigasi sebesar 40–60% dan menghilangkan kelas kesalahan terkait siklus hidup Fragment.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga