Ang NavController ay ang sentral na bahagi ng library ng Navigation Compose na namamahala sa stack ng nabigasyon at estado ng back stack sa mga Android application. Sa pamamagitan ng NavController ay isinasagawa ang mga transition sa pagitan ng mga screen, pagbabalik sa mga nakaraang pahina, at pagpapadala ng data sa pagitan ng mga ruta. Ayon sa Android Developers (2025), ang NavController ay isang mandatoryong elemento ng anumang Compose application na may higit sa isang screen. Ang controller ay ginagawa sa pamamagitan ng rememberNavController(), ipinapasa sa NavHost, at available para tawagan ang navigate() mula sa anumang punto ng komposisyon. Ang built-in na suporta para sa SavedStateHandle ay awtomatikong nagse-save ng estado ng ViewModel sa reconfiguration.
Mga Pangunahing Punto
NavController — ay isang klase mula sa library ng Navigation Compose na nagpapatupad ng controller ng nabigasyon para sa mga Compose application. Ang NavController ay namamahala sa stack ng NavBackStackEntry, kung saan ang bawat entry ay naglalaman ng ruta, mga argumento, at estado ng screen. Ang controller ay sumusuporta sa mga pangunahing operasyon ng nabigasyon: transition, pagbabalik, pagpapalit, at paglilinis.
Hindi tulad ng View system, kung saan ang nabigasyon ay ginagawa sa pamamagitan ng FragmentManager o Intent, ang NavController ay gumagana nang eksklusibo sa konteksto ng Compose. Ang back stack ay iniimbak bilang isang graph ng NavDestination, hindi isang stack ng Fragment. Ito ay nag-aalis ng overhead ng paglikha at pagsira ng Fragment, at pinapasimple ang pag-test — ang NavController ay maaaring i-mock sa pamamagitan ng TestNavHostController.
Ang NavController ay malapit na nauugnay sa NavHost — ang lalagyan na nagre-render ng kasalukuyang screen mula sa graph. Kung wala ang NavHost, hindi maaaring magpakita ang NavController ng mga composable function, ngunit pinapanatili ang kakayahang mamahala ng stack. Sa tipikal na arkitektura, ang NavController ay ginagawa sa antas ng Activity o pangunahing composable at ipinapasa pababa sa puno ng komposisyon sa pamamagitan ng mga parameter.
Ayon sa Google, ang NavController ay dumaan sa ilang major release. Ang bersyon 2.8.0 ay nagdagdag ng Type-Safe Navigation, bersyon 2.9.0 — suporta para sa predictive back gesture (Android 14+). Ang controller ay compatible sa Material3 Scaffold at BottomNavigation. Para sa mga multi-module na proyekto, ang NavController ay ipinapasa sa pamamagitan ng DI (Hilt/Koin) o mga parameter ng konstruktor.
Ang NavController ay ginagawa sa pamamagitan ng composable function na rememberNavController(). Ang function ay nagbabalik ng isang instance ng NavHostController (tagapagmana ng NavController) na nakatali sa lifecycle ng kasalukuyang composable. Sa paglabas mula sa komposisyon, ang controller ay nililinis. Para i-save ang controller sa reconfiguration, gamitin ang rememberSaveable o ViewModel.
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "main"
) {
composable("main") { MainScreen(navController) }
composable("details") { DetailsScreen(navController) }
}
}
Ang configuration ng NavController ay kinabibilangan ng: NavHostController (pangunahing), TestNavHostController (pag-test) at ScopedNavController (anak para sa nested graphs). Para sa BottomNavigation, ang NavController ay dapat na nag-iisa para sa buong application — ang paggawa ng bagong controller sa bawat tab ay magdudulot ng pagkawala ng stack. Para sa pagpapasa ng controller sa mga nested screen, gamitin ang parameter ng function, hindi CompositionLocalProvider, upang mapanatili ang pagiging madaling mabasa.
Para sa pag-test ng nabigasyon, gamitin ang TestNavHostController na may compose-test-rule. Ang controller ay nagpapahintulot sa pag-set ng paunang ruta at pag-verify na ang navigate() ay tumawag sa inaasahang transition. Ang pag-test ng NavController ay hindi nangangailangan ng emulator — ito ay gumagana sa mga Semantics matcher ng Compose Test.
Ang pamamaraang navigate(route: String) — pangunahing paraan ng nabigasyon sa NavController. Tumatanggap ng string ng ruta, opsyonal na NavOptions at Navigator.Extras. Ang NavOptions ay namamahala sa pag-uugali ng transition: launchSingleTop (huwag i-duplicate ang ruta sa stack), popUpTo (linisin ang stack hanggang ruta), restoreState (ibalik ang dating estado).
Ang NavOptions ay itinakda sa pamamagitan ng syntax ng builder: NavOptionsBuilder. Mga pangunahing parameter: popUpTo (route + inclusive/saveState), launchSingleTop (Boolean, true — huwag gumawa ng duplicate), restoreState (ibalik ang estado sa pagbabalik). Kung walang popUpTo, bawat navigate() ay nagdaragdag ng entry sa stack, na humahantong sa akumulasyon ng back stack at hindi tamang pag-uugali ng Back button.
navController.navigate("profile/42") {
popUpTo("main") { saveState = true }
launchSingleTop = true
restoreState = true
}
Ang Navigator.Extras ay nagpapahintulot sa pagpapadala ng karagdagang data na hindi bahagi ng ruta: shared element para sa animation, mga flag ng Intent, Pac-Man bundle. Ang Extras ay bihirang ginagamit — pangunahin para sa integrasyon sa Accompanist Animation o custom na Navigator. Para sa karamihan ng mga senaryo, sapat na ang string ng ruta at NavOptions.
popBackStack() — pamamaraan para sa pagbabalik sa nakaraang screen. Kung walang argumento, tinatanggal ang tuktok na entry ng stack at nagbabalik ng true kung matagumpay ang pagtanggal. Kung walang laman ang stack — ang pamamaraan ay nagbabalik ng false, at ang Activity ay isinasara (katulad ng super.onBackPressed()).
Ang overload na bersyon na popBackStack(route: String, inclusive: Boolean) ay tinatanggal ang lahat ng entry hanggang sa tinukoy na ruta. Kung inclusive = true — ang tinukoy na ruta mismo ay tinatanggal din. Ang pamamaraan ay nagbabalik ng Boolean — true kung natagpuan at natanggal ang mga entry. Ang bersyon na may inclusive ay kapaki-pakinabang para sa mga senaryo ng “paglabas sa pangunahing screen” pagkatapos ng awtorisasyon o pagkumpleto ng order.
| Pamamaraan | Paglalarawan | Halimbawa |
|---|---|---|
| popBackStack() | Bumalik ng isang screen pabalik | navController.popBackStack() |
| popBackStack(route, false) | Linisin hanggang ruta (mananatili ang ruta) | popBackStack("home", false) |
| popBackStack(route, true) | Linisin hanggang at kasama ang ruta | popBackStack("home", true) |
| navigate(route) { popUpTo(route) { inclusive = true } } | Transition na may buong paglilinis | navigate("login") { popUpTo(0) { inclusive = true } } |
Para sa paghawak ng system Back button (hardware back button), gamitin ang BackHandler mula sa Compose. Ang BackHandler ay tumatanggap ng enabled at onBack — callback na tinatawag kapag pinindot. Para sa Android 14+ ginagamit ang PredictiveBackGesture, na isinama sa pamamagitan ng NavController mula bersyon 2.9.0. Ang Predictive back ay nagdaragdag ng preview animation ng pagbabalik.
SavedStateHandle — ay isang mekanismo para sa pag-save ng estado ng ViewModel sa nabigasyon at reconfiguration. Ang NavController ay awtomatikong nagbibigay ng SavedStateHandle para sa bawat NavBackStackEntry. Sa pamamagitan ng SavedStateHandle, iniimbak ng ViewModel ang estado ng screen at ibinabalik ito sa pagbabalik (restoreState = true).
Sa Navigation Compose, ang SavedStateHandle ay ginagamit kasama ng ViewModel: ang ViewModel ay sinisimulan sa pamamagitan ng SavedStateHandle na ipinapasa mula sa backStackEntry. Sa paglipat sa ibang screen at pagbabalik (na may restoreState), natatanggap ng ViewModel ang naka-save na estado, hindi ito nilikhang muli. Ito ay kritikal para sa mga screen na may input ng data, mga filter, o scroll.
class ProfileViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val userId: String = savedStateHandle.get<String>("userId") ?: ""
var searchQuery by savedStateHandle.getStateFlow("search", "")
.collectAsState()
}
Ang SavedStateHandle ay sumusuporta sa mga primitive na uri, String, Bundle, at Parcelable. Para sa mga kumplikadong bagay, i-save lamang ang ID, at i-load ang kumpletong data mula sa repository. Ang limitasyon ng SavedStateHandle ay humigit-kumulang 1 MB, ang paglampas ay nagdudulot ng TransactionTooLargeException. Para sa malalaking volume, gamitin ang Room o DataStore sa halip na mag-save sa handle.
Mahalaga: Ang SavedStateHandle ay nagse-save ng estado lamang kapag ginagamit ang restoreState = true sa NavOptions. Kung hindi tinukoy ang restoreState, sa pagbabalik ang ViewModel ay nilikhang muli na may mga default na halaga. Para sa paglipat ng BottomNavigation na may restoreState, iniimbak ng NavController ang estado ng bawat tab at ibinabalik ito sa paulit-ulit na pagpili.
currentBackStackEntryAsState() — function na nagbabalik ng State<NavBackStackEntry?>, na naa-update sa bawat pagbabago ng kasalukuyang ruta. Ito ang pangunahing mekanismo ng synchronisasyon ng UI sa nabigasyon: Binibigyang-diin ng BottomNavigation ang aktibong elemento, ina-update ng Toolbar ang pamagat, nagsasara ang Drawer sa transition.
Ang function ay gumagana sa pamamagitan ng snapshotFlow at collectAsState: sa pagbabago ng back stack, muling kinomposisyon ng Compose ang mga naka-subscribe na elemento. Mahalaga: Ang currentBackStackEntryAsState() ay naa-update lamang pagkatapos makumpleto ang animation ng transition. Para sa agarang pag-update, gamitin ang currentDestination, na nagbabago nang sabay sa navigate(), ngunit hindi sumusuporta sa estado.
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Text(
text = when (currentRoute) {
"home" -> "Home"
"profile" -> "Profile"
else -> ""
}
)
Para sa pag-access sa mga argumento ng kasalukuyang ruta, gamitin ang navBackStackEntry?.arguments. Ito ay maginhawa sa BottomNavigation: ang selectedItem ay kinakalkula batay sa currentRoute. Para sa debugging ng nabigasyon, gamitin ang NavController.addOnDestinationChangedListener(), na nagla-log ng bawat transition. Sa production, iwasan ang mga subscription sa loob ng maraming composable — gumawa ng isang source sa ViewModel at ipasa ang State sa UI.
Mga Madalas Itanong
Sa teknikal na paraan oo, ngunit hindi inirerekomenda. Ang isang NavController ay nagsisiguro ng pare-parehong back stack at pinapasimple ang debugging. Ang maraming controller ay makatwiran lamang para sa mga nested graph na may hiwalay na nabigasyon (halimbawa, modal bottom sheet na may sariling stack).
Ipasa ang NavController sa ViewModel sa pamamagitan ng konstruktor o DI. Gayunpaman, mas mainam na magpasa lamang ng mga callback function (onNavigate, onBack), hindi ang NavController mismo — pinapasimple nito ang pag-test. Para sa mga kaganapan, gamitin ang Channel<NavEvent> sa ViewModel at kolektahin sa UI.
Ang problema ay nasa lifecycle: kung ang NavController ay hindi pa nasisimulan (ang NavHost ay hindi naitayo), ang navigate() ay hindi pinapansin. Gamitin ang LaunchedEffect para tawagan ang nabigasyon pagkatapos mag-load ng data, hindi sa loob ng coroutine na may arbitrary na lifecycle.
Tawagan ang navController.navigate("target") { popUpTo(0) { inclusive = true } }. Ang parameter na popUpTo(0) ay ganap na nililinis ang stack, inclusive = true ay tinatanggal din ang paunang entry. Ang flag na launchSingleTop = true ay pumipigil sa pagdoble ng bagong ruta.
NavHostController — tagapagmana ng NavController na may mga karagdagang pamamaraan para sa NavHost (halimbawa, setOnBackStackChangedListener). NavController — base class na maaaring gamitin sa labas ng NavHost para sa programmatic na pamamahala ng stack. Sa karamihan ng mga kaso, ginagamit ang NavHostController.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din