NavController — esensya, mga pamamaraan, at pamamahala ng nabigasyon sa Jetpack Compose

May-akda: IT Sectr Nai-publish: 2026-06-29 Oras ng pagbabasa: 7 min

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 — sentral na controller ng nabigasyon ng Compose, namamahala sa back stack at mga transition sa pagitan ng mga screen
  • navigate() — pangunahing pamamaraan para sa transition sa ruta na may suporta sa NavOptions para sa pamamahala ng stack
  • popBackStack() — pagbabalik sa nakaraang screen na may opsyonal na paglilinis hanggang sa tinukoy na ruta
  • SavedStateHandle — integrasyon sa ViewModel para sa pag-save ng estado ng screen sa nabigasyon
  • currentBackStackEntryAsState() — pagmamasid sa kasalukuyang ruta para sa synchronisasyon ng UI

Ano ang NavController sa Jetpack Compose?

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.

kotlin
@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.

kotlin
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: pamamahala ng pagbabalik at paglilinis ng stack

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.

PamamaraanPaglalarawanHalimbawa
popBackStack()Bumalik ng isang screen pabaliknavController.popBackStack()
popBackStack(route, false)Linisin hanggang ruta (mananatili ang ruta)popBackStack("home", false)
popBackStack(route, true)Linisin hanggang at kasama ang rutapopBackStack("home", true)
navigate(route) { popUpTo(route) { inclusive = true } }Transition na may buong paglilinisnavigate("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: pag-save ng estado ng screen

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.

kotlin
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.

Pagmamasid sa kasalukuyang ruta sa pamamagitan ng currentBackStackEntryAsState

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.

kotlin
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

Maaari bang gumawa ng maraming NavController sa isang Activity?

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).

Paano ipasa ang NavController sa pamamagitan ng ViewModel?

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.

Bakit hindi gumagana ang navigate pagkatapos ng asynchronous na operasyon?

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.

Paano linisin ang buong back stack at pumunta sa bagong screen?

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.

Ano ang pagkakaiba sa pagitan ng NavHostController at NavController?

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

  • NavController — sentral na bahagi ng Navigation Compose, namamahala sa stack ng mga ruta at transition sa pagitan ng mga screen
  • navigate() ay nagsasagawa ng transition na may mga setting na popUpTo, launchSingleTop at restoreState sa pamamagitan ng NavOptions
  • popBackStack() ay namamahala sa pagbabalik: solong hakbang o mass cleaning hanggang sa tinukoy na ruta na may inclusive
  • SavedStateHandle ay sumasama sa ViewModel para sa awtomatikong pag-save ng estado ng screen sa nabigasyon
  • currentBackStackEntryAsState() ay nagbibigay ng reaktibong pagmamasid sa kasalukuyang ruta para sa synchronisasyon ng UI
  • BackHandler ay humahawak ng system Back button, at PredictiveBackGesture ay sinusuportahan mula NavController 2.9.0
  • Para sa pag-test, gamitin ang TestNavHostController na may compose-test-rule at Semantics matcher

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.

Pag-usapan ang proyekto

Basahin din