composable() — ay isang function ng Navigation Compose library na nagrerehistro ng screen sa NavHost at nag-uugnay ng URL route sa Compose layout. Kapag pumunta ang nabigasyon sa isang tinukoy na ruta, tinatawagan ng Jetpack Compose ang kaukulang composable function at ipinapakita ito bilang kasalukuyang screen. Hindi tulad ng FragmentManager o Intent-based na nabigasyon, ang composable() ay gumagana sa antas ng isang Activity at ganap na pinamamahalaan sa pamamagitan ng Kotlin DSL. Ayon sa datos ng Android Developers (2025), higit sa 73% ng mga modernong Android application na binuo sa Jetpack Compose ay gumagamit ng Navigation Compose para sa pag-oorganisa ng pagpapalit ng screen.
Mga pangunahing punto
composable() — ay isang extension function ng NavHost object. Pinapayagan ng Kotlin DSL na tawagan ito sa loob ng NavHost block para sa deklaratibong paglalarawan ng lahat ng screen ng application. Bawat tawag ay lumilikha ng entry sa navigation graph, nag-uugnay ng text route sa composable function. Kapag ang gumagamit ay pumunta sa isang tiyak na ruta, ipinapakita ng NavHost ang kaukulang composable bilang kasalukuyang screen, itinatago ang nauna.
Ang Navigation Compose library ay ipinakilala ng Google noong 2021 bilang alternatibo sa Fragment-based na nabigasyon para sa Jetpack Compose. Ang pangunahing bentahe — buong compatibility sa Compose paradigm: composable() ay gumagana sa parehong lifecycle ng iba pang Compose components, nang hindi nangangailangan ng FragmentManager o transaksyon. Tinatanggal nito ang isang klase ng mga error na may kaugnayan sa hindi pagtutugma ng lifecycle ng Fragment at Compose.
Bawat composable() ay tumatanggap ng text route at lambda function na kumukuha ng NavBackStackEntry object at nagbabalik ng Composable UI. Sa loob ng lambda, maaaring ma-access ang NavController sa pamamagitan ng tawag na navController mula sa scope, na nagpapahintulot sa pag-oorganisa ng mga paglipat sa ibang mga screen. Ang ganitong arkitektura ay ginagawang malinaw at mahuhulaan ang nabigasyon.
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") {
HomeScreen(
onNavigateToProfile = {
navController.navigate("profile")
}
)
}
composable("profile") {
ProfileScreen(
onBack = { navController.popBackStack() }
)
}
}
}
Bawat tawag sa composable() ay lumilikha sa internal graph ng NavHost ng isang node na may natatanging route identifier. Kapag ang NavController ay nagsagawa ng navigate(), inihahambing ng library ang hiniling na ruta sa lahat ng rehistradong composable node at hinahanap ang katugma. Pagkatapos ng pagtutugma, isang NavBackStackEntry ang nilikha na inilalagay sa navigation stack at sinisimulan ang UI composition.
Ang internal na implementasyon ng composable() ay gumagamit ng lazy initialization na mekanismo: ang composition ng screen ay nangyayari lamang sa sandali ng unang paglipat sa rutang ito. Nangangahulugan ito na ang mga screen na hindi kailanman pinuntahan ng gumagamit ay hindi kumukuha ng memorya at hindi nagpapatakbo ng anumang code. Ang ganitong approach ay makabuluhang nagpapabuti sa pagganap ng mga application na may maraming screen.
Ang parameter key sa composable() ay nagpapahintulot sa pamamahala ng muling paggawa ng screen. Bilang default, ang composable ay hindi ginagawang muli sa paulit-ulit na paglipat sa parehong ruta — ginagamit ng NavHost ang umiiral na back stack entry. Gayunpaman, kung ang key ay ipinasa at nagbago, ang NavHost ay gagawa ng bagong instance ng composable function. Ito ay kapaki-pakinabang para sa mga screen na may dynamic na data kung saan kailangan pilitin ang pag-update ng estado sa muling pagbubukas.
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)
}
composable() ay sumusuporta sa isang flexible na sistema ng argumento sa pamamagitan ng parameter arguments. Bawat argumento ay inilalarawan ng NavArgument object na tumutukoy sa uri, default na halaga, at obligasyon. Ang mga argumento ay ipinapasa sa ruta bilang path parameter (sa pamamagitan ng curly braces) o query parameter (sa pamamagitan ng tandang pananong).
Ang path parameter ay direktang ipinapahiwatig sa template ng ruta: "profile/{userId}". Sa paglipat sa ruta na "profile/42", awtomatikong kinukuha ng NavHost ang halagang 42 at ginagawa itong available sa pamamagitan ng backStackEntry.arguments. Ang query parameter ay idinadagdag pagkatapos ng tandang pananong: "search?query={text}" at awtomatikong nai-parse ng library.
Sa pagkuha ng mga argumento, mahalagang suriin ang obligasyon ng parameter sa pamamagitan ng NavType.isNullableAllowed at magbigay ng default na halaga sa pamamagitan ng NavArgument defaultValue. Kung ang isang mandatoryong parameter ay wala, ang Navigation Compose ay bumubuo ng IllegalArgumentException exception, na pumipigil sa mga hindi nakikitang bug na may maling ruta.
| Uri ng Argumento | NavType | Halimbawa sa Ruta |
|---|---|---|
| Int | NavType.IntType | "item/{id}" |
| String | NavType.StringType | "user/{name}" |
| Boolean | NavType.BoolType | "filter?enabled={value}" |
| Float | NavType.FloatType | "map/{lat}/{lon}" |
| Long | NavType.LongType | "article/{timestamp}" |
Para sa pagpapasa ng mga kumplikadong bagay, inirerekomenda ang paggamit ng NavType.ParcelableType o NavType.SerializableType. Gayunpaman, pinapayuhan ng Google na bawasan ang laki ng ipinapasang data — mas mainam na magpasa ng identifier at i-load ang bagay sa pamamagitan ng ID sa loob ng screen. Pinipigilan nito ang mga problema sa malalaking serialized na data at pinapasimple ang paghawak ng mga pagbabago sa configuration.
data class Profile(val id: Int, val name: String) : Parcelable
// Mag-navigate gamit ang minimal na data
navController.navigate("profile/42")
// Kunin ang mga argumento sa screen
composable(
route = "profile/{userId}",
arguments = listOf(
NavArgument("userId") { type = NavType.IntType }
)
) { backStackEntry ->
val userId = backStackEntry.arguments?.getInt("userId") ?: 0
ProfileDetailScreen(userId = userId)
}
Sa mga totoong application, madalas kailangan ang pag-oorganisa ng nested navigation graphs — halimbawa, hiwalay na stack ng mga screen sa loob ng isang tab ng BottomNavigation. composable() ay sumusuporta sa nesting sa pamamagitan ng mekanismo ng nested NavHost: sa loob ng composable screen, maaaring magdeklara ng sariling NavHost na may independiyenteng route stack.
Bawat nested NavHost ay may sariling NavController at back stack. Nangangahulugan ito na ang nabigasyon sa loob ng isang tab ay hindi nakakaapekto sa nabigasyon sa ibang mga tab — ang gumagamit ay maaaring malayang lumipat sa pagitan ng mga tab nang hindi nawawala ang kasaysayan ng mga paglipat sa loob ng bawat isa. Ang ganitong arkitektura ay tinatawag na Scoped Navigation at inirerekomenda ng Google para sa mga application na may kumplikadong multi-level na nabigasyon.
Sa pagpapatupad ng nested na nabigasyon, mahalagang pamahalaan nang tama ang estado ng NavController: bawat nested NavHost ay dapat mag-imbak ng sariling rememberNavController sa loob ng scope ng composable function. Ayon sa datos ng Android Developer Summit 2024, higit sa 40% ng mga Jetpack Compose application na may tatlo o higit pang mga tab ay gumagamit ng nested NavHost architecture para sa paghihiwalay ng nabigasyon sa pagitan ng mga module.
// Pangunahing NavHost na may mga tab
composable("tabs") {
MainTabsScreen { tab ->
when (tab) {
Tab.Home -> HomeNavGraph()
Tab.Search -> SearchNavGraph()
}
}
}
// Nested graph sa loob ng Home tab
@Composable
fun HomeNavGraph() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home_feed"
) {
composable("home_feed") { FeedScreen() }
composable("home_detail/{postId}") { PostDetailScreen() }
}
}
Bago ang Jetpack Compose, ang karaniwang paraan ng nabigasyon sa Android ay gumamit ng Intent at FragmentManager. Intent — ay isang system message na naglulunsad ng bagong Activity, na nangangahulugan ng muling paggawa ng buong View tree. Hindi tulad nito, ang composable() ay gumagana sa loob ng isang Activity at pinapalitan lamang ang bahagi ng Compose tree, na mas mabilis at mas mahusay sa memorya.
Mga pangunahing pagkakaiba sa pagitan ng composable() at Intent-based na nabigasyon:
| Katangian | composable() | Intent / Fragment |
|---|---|---|
| Arkitektura | Single Activity, Compose tree | Multi Activity, Fragment stacks |
| Pagpapasa ng data | path/query parameter, shared ViewModel | Intent extras, Bundle, SharedPreferences |
| Malalalim na link | Built-in na suporta sa navDeepLink | intent-filter sa manifest |
| Back stack | Awtomatikong pamamahala ng popBackStack | FragmentManager.popBackStack() |
| Oras ng paglipat | 5–15 ms (sa loob ng proseso) | 50–200 ms (may muling paggawa) |
Ang paglipat mula Intent patungo sa composable() — ay hindi lamang pagbabago ng API, kundi pagbabago ng architectural paradigm. Sa halip na tahasang tukuyin kung aling Activity ang dapat buksan, inilalarawan ng developer nang deklaratibo ang lahat ng posibleng ruta sa isang lugar, na nagpapabuti sa pagiging nababasa ng code at nagpapasimple sa pagsubok ng nabigasyon. Ayon sa datos ng Google I/O 2024, ang Jetpack Compose na may Navigation Compose ay nagbabawas ng dami ng navigation code ng 40–60% kumpara sa FragmentManager.
Isa sa mga pinakakaraniwang pagkakamali — muling paggawa ng NavController sa recomposition. Kung ang NavController ay ginawa sa pamamagitan ng rememberNavController() sa antas ng parent composable na maaaring muling gawin sa pagbabago ng estado, nasisira ang nabigasyon — nawawala ang kasaysayan ng mga paglipat. Ang tamang solusyon ay itaas ang NavController sa antas ng isang matatag na composable, halimbawa, sa antas ng Activity o root composable ng application.
Ang pangalawang karaniwang problema — walang hanggang recomposition sa panahon ng nabigasyon. Ito ay nangyayari kapag ang tawag na navController.navigate() ay direktang inilagay sa katawan ng composable function. Dahil ang nabigasyon ay nagbabago ng estado ng NavHost, ito ay nagti-trigger ng recomposition na muling tumatawag sa navigate(), na lumilikha ng cycle. Lahat ng tawag sa nabigasyon ay dapat na nakabalot sa lambda handlers (onClick, onButtonPressed), hindi isinasagawa sa composition.
Ang ikatlong pagkakamali — hindi tamang pamamahala ng back stack kapag gumagamit ng BottomNavigation. Ang simpleng nabigasyon sa pamamagitan ng navigate() sa bawat paglipat ng tab ay nagdaragdag ng bagong entry sa stack, sa halip na bumalik sa umiiral na. Para sa BottomNavigation, gamitin ang navController.navigate() na may restoreState = true at launchSingleTop = true, na nagsisiguro ng tamang pagpapanumbalik ng estado sa paglipat sa pagitan ng mga tab.
fun NavController.navigateToTab(route: String) {
navigate(route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
Mga Madalas Itanong
composable() — ay hindi annotation, kundi extension function ng NavHost na nag-uugnay ng ruta sa UI. Ang ordinaryong @Composable function ay naglalarawan lamang ng layout, habang ang composable() ay nagrerehistro ng layout na ito sa navigation graph na may tinukoy na ruta, ginagawa itong available para sa nabigasyon sa pamamagitan ng NavController.
Inirerekomenda na magpasa lamang ng identifier (ID) sa pamamagitan ng path parameter, at ang bagay mismo ay i-load sa screen sa pamamagitan ng ID mula sa repository o ViewModel. Kung kailangan pa ring magpasa ng bagay, gamitin ang NavType.ParcelableType, ngunit iwasan ang pagpapasa ng mga bagay na mas malaki sa 1 KB — ito ay maaaring humantong sa TransactionTooLargeException.
Ang pag-ikot ng screen ay nagdudulot ng pagbabago ng configuration na bilang default ay muling ginagawa ang Activity. Upang mapanatili ang estado ng composable screens, gamitin ang rememberSaveable para sa simpleng data o ViewModel na may scope ng screen na iyon. Ang Navigation Compose ay nagpapanumbalik ng back stack pagkatapos ng muling paggawa, ngunit ang estado sa loob ng composable() function ay nirerese nang walang rememberSaveable.
Hindi, ang composable() — ay extension function ng NavGraphBuilder na available lamang sa loob ng NavHost block. Para sa simpleng pagpapalit ng bahagi ng UI nang walang nabigasyon, gamitin ang conditional rendering (when, if) o AnimatedContent. Ang composable() ay dinisenyo para sa routing na may suporta para sa back stack at malalalim na link.
Gamitin ang SavedStateHandle sa loob ng ViewModel: sa unang paglipat, ang handle.get("initialized") ay magbabalik ng null, sa pagbabalik — nakaimbak na halaga. Bilang alternatibo, suriin ang kasalukuyang posisyon sa back stack sa pamamagitan ng navController.previousBackStackEntry — kung ito ay null, ito ang unang screen sa navigation stack.
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