Fragment Lifecycle — isang mahigpit na tinukoy na pagkakasunod-sunod ng mga pamamaraan ng callback na tinatawag ng Android sa buong buhay ng Fragment: mula sa paggawa (onAttach) hanggang sa kumpletong pag-alis (onDetach). Ang Fragment ay may mas kumplikadong siklo ng buhay kaysa sa Activity — kabilang dito ang 11 estado at 7 pangunahing callback. Ang Fragment Lifecycle ay pinamamahalaan sa pamamagitan ng FragmentManager at malapit na nauugnay sa siklo ng buhay ng Activity na naglalaman nito. Ayon sa data ng Google, ang Fragment ay ginagamit sa 74% ng mga Android application na tumatakbo sa API Level 21+, na ginagawang kinakailangan ang pag-unawa sa Fragment Lifecycle para sa propesyonal na pag-develop ng Android. Ang dokumentasyon ng Android tungkol sa Fragment Lifecycle ay naglalarawan ng lahat ng estado at garantiya ng tawag.
Mga pangunahing punto
Fragment Lifecycle ay isang set ng magkakaugnay na estado at pamamaraan na pinagdadaanan ng bawat instance ng Fragment mula sa sandali ng paggawa hanggang sa pagkawasak. Hindi tulad ng Activity, ang siklo ng buhay ng Fragment ay nakatali sa dalawang konteksto: ang Fragment mismo (nabubuhay mula onAttach hanggang onDetach) at ang View nito (nabubuhay mula onCreateView hanggang onDestroyView). Ang paghihiwalay na ito ay isang pangunahing katangian ng Fragment, na nagpapahintulot na mabuhay sa pagkawasak ng View sa pag-ikot ng screen nang hindi sinisira ang Fragment mismo.
Buong pagkakasunod-sunod ng mga callback ng Fragment:
Ayon sa Google, ang karaniwang fragment sa modernong application ay dumadaan sa buong siklo ng 3–5 beses bawat session ng gumagamit (dahil sa mga pag-ikot ng screen at nabigasyon). Ang tamang paghawak ng lahat ng yugto ay batayan ng katatagan ng UI.
Ang FragmentManager ay namamahala ng Fragment sa pamamagitan ng limang pangunahing estado, tinukoy sa klase ng Fragment.State. Ang bawat estado ay tumutugma sa isang tiyak na set ng mga callback na naisagawa.
| Estado | Kahulugan | Mga naisagawang callback |
|---|---|---|
| INITIALIZED | Fragment nagawa, ngunit wala pang View | onAttach, onCreate |
| CREATED | View nagawa, ngunit hindi nakikita ang Fragment | + onCreateView, onViewCreated |
| STARTED | Fragment nakikita, ngunit hindi aktibo | + onStart |
| RESUMED | Fragment aktibo, nakikipag-ugnayan sa gumagamit | + onResume |
| DESTROYED | Fragment nawasak | + onDestroyView, onDestroy, onDetach |
Ang FragmentManager ay naglilipat ng Fragment sa pagitan ng mga estado depende sa mga aksyon ng gumagamit at mga kaganapan ng system. Kapag nagdadagdag ng Fragment sa isang lalagyan, sunod-sunod itong dumadaan sa INITIALIZED → CREATED → STARTED → RESUMED. Kapag inaalis — RESUMED → STARTED → CREATED → DESTROYED.
Ang estado CREATED — espesyal: ang View ay maaaring masira (pagkatapos ng onDestroyView), ngunit ang Fragment mismo ay nananatili sa estado ng CREATED (pagkatapos ng onDestroyView, bago ang onDestroy). Ito ay nagpapahintulot sa FragmentManager na panatilihin ang Fragment sa memorya nang walang View, na kinakailangan para mabuhay sa mga pag-ikot ng screen.
Ang Fragment Lifecycle at Activity Lifecycle ay malapit na nauugnay, ngunit may mga pangunahing pagkakaiba. Ang Fragment ay laging nabubuhay sa loob ng Activity, at ang siklo ng buhay nito ay nakasalalay sa Activity-host, ngunit hindi katulad nito.
| Aspekto | Activity | Fragment |
|---|---|---|
| Bilang ng mga callback | 7 (onCreate … onDestroy) | 11 (onAttach … onDetach) |
| Hiwalay na Lifecycle para sa View | Hindi | Oo (viewLifecycleOwner) |
| Nabubuhay sa pag-ikot | Hindi (nasira) | Oo (ViewModel + Fragment nabubuhay) |
| Pag-asa sa host | Hindi | Nakadepende sa Activity Lifecycle |
| Pag-save ng estado | onSaveInstanceState | onSaveInstanceState (fragment) |
| Pamamahala | Sistema | FragmentManager |
Pangunahing praktikal na pagkakaiba: sa pag-ikot ng screen, ang Activity ay ganap na nawasak (onDestroy) at ginawang muli (onCreate). Ang Fragment sa pag-ikot ay dumadaan sa onDestroyView (View ay nawasak) → onCreateView (View ay ginawang muli), ngunit ang Fragment mismo at ang ViewModel nito ay nananatiling buhay. Ginagawa nitong perpektong lalagyan ang Fragment para sa lohika ng UI na dapat mabuhay sa mga pagbabago sa konpigurasyon.
Pagkakasunod-sunod ng mga tawag sa pag-ikot ng screen: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity nawasak) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.
FragmentManager — ang sentral na klase na responsable para sa pagdaragdag, pag-alis, pagpapalit ng mga fragment at pamamahala ng kanilang mga estado. Ang FragmentManager ay nagpapanatili ng stack ng BackStack at ginagarantiyahan ang tamang pagkakasunod-sunod ng mga callback sa mga transaksyon. Ang bawat Activity at bawat nested Fragment ay may sariling FragmentManager.
Pangunahing operasyon ng FragmentManager:
BackStack — stack ng mga transaksyon ng FragmentManager. Kapag pinindot ang system button na “Bumalik”, ang huling transaksyon sa BackStack ay binabaligtad (popBackStack()). Ang Fragment na inalis sa pamamagitan ng popBackStack ay naibabalik. Kung walang laman ang BackStack, ang pagpindot sa “Bumalik” ay nagtatapos sa Activity.
Ayon sa Google, 78% ng mga problema sa Fragment (pagdoble, mga blangkong screen, IllegalStateException) ay nauugnay sa hindi tamang paggamit ng FragmentManager. Pangunahing panuntunan: isagawa ang mga transaksyon sa pamamagitan ng commit() (asynchronously) o commitNow() (synchronously) depende sa konteksto. Ang commit() ay ginagarantiyahan ang tamang pagkakasunod-sunod sa maraming transaksyon.
Ang Fragment ay sumusuporta sa sarili nitong mekanismo ng pag-save ng estado sa pamamagitan ng onSaveInstanceState, na gumagana nang independyente sa Activity. Ang Fragment ay nagse-save ng estado sa Bundle, na ipinapasa sa onCreate at onCreateView sa pagpapanumbalik.
Kailan nagse-save ng estado ang Fragment:
Makabagong diskarte: gamitin ang SavedStateHandle sa ViewModel para sa pag-save ng estado ng Fragment. Ang SavedStateHandle ay awtomatikong nagse-save at nagpapanumbalik ng data sa pag-ikot ng screen at process death, nang hindi nangangailangan ng manu-manong onSaveInstanceState. Inirerekomenda ng Google ang SavedStateHandle bilang ginustong paraan ng pag-save ng estado ng UI sa Fragment.
setRetainInstance (luma na mula Fragment 1.3): dati ang Fragment ay maaaring mapanatili sa pamamagitan ng setRetainInstance(true) sa pag-ikot ng screen. Ang diskarteng ito ay pinalitan ng ViewModel + SavedStateHandle, na mas maaasahan at hindi nangangailangan ng espesyal na pagsasaayos.
viewLifecycleOwner — Lifecycle na nakatali sa View ng Fragment (mula onCreateView hanggang onDestroyView). Ito ay isang pangunahing mahalagang konsepto: ang mga subscription ng LiveData/Flow na ginawa sa pamamagitan ng viewLifecycleOwner ay awtomatikong kinakansela sa pagkawasak ng View (onDestroyView), ngunit hindi naaapektuhan ang Fragment mismo.
Pagkakaiba ng viewLifecycleOwner at lifecycle ng Fragment:
Bakit ito mahalaga: kung mag-subscribe ka sa LiveData sa pamamagitan ng lifecycle ng Fragment (this), pagkatapos ng onDestroyView ang subscription ay nananatiling aktibo at LiveData ay susubukang i-update ang null View, na nagdudulot ng NPE. Ang subscription sa pamamagitan ng viewLifecycleOwner ay ginagarantiyahan na pagkatapos ng onDestroyView walang magaganap na UI update.
Panuntunan: sa Fragment, laging gamitin ang viewLifecycleOwner para sa mga subscription ng LiveData, Flow at coroutine na may kaugnayan sa UI. Para sa mga coroutine ng ViewModel, gamitin ang viewModelScope — ito ay nakatali sa ViewModel, hindi sa Fragment.
Nagpapakita ng tamang pagsisimula ng UI at subscription ng LiveData sa pamamagitan ng viewLifecycleOwner.
class UserListFragment : Fragment() {
private val viewModel: UserListViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_user_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val button: Button = view.findViewById(R.id.load_button)
button.setOnClickListener { viewModel.loadUsers() }
viewModel.users.observe(viewLifecycleOwner) { users ->
Log.d("UserListFragment", "Pag-update ng listahan: ${users.size} mga gumagamit")
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("UserListFragment", "onDestroyView: View nawasak")
}
}
Ang Fragment ay nagpapalaki ng layout sa onCreateView, nag-aayos ng UI at nag-subscribe sa LiveData sa onViewCreated. Ang subscription sa pamamagitan ng viewLifecycleOwner — isang sapilitang kinakailangan para maiwasan ang pagtagas ng memorya. Ang onDestroyView ay nag-log ng pagkawasak ng View — kumpirmasyon na ang Fragment ay nabubuhay sa pag-ikot ng screen.
Nagpapakita ng pagdaragdag ng Fragment sa pamamagitan ng FragmentManager sa Activity, pagpapalit ng BackStack at pagpapanumbalik.
class HostActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, HomeFragment())
.addToBackStack(null)
.commit()
}
}
fun openDetail(userId: String) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, DetailFragment.newInstance(userId))
.addToBackStack(null)
.commit()
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
} else {
super.onBackPressed()
}
}
}
class DetailFragment : Fragment() {
companion object {
fun newInstance(userId: String): DetailFragment {
return DetailFragment().apply {
arguments = Bundle().apply { putString("user_id", userId) }
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val userId = arguments?.getString("user_id")
Log.d("DetailFragment", "Pag-load ng mga detalye ng gumagamit: $userId")
}
}
Ang Activity ay gumagamit ng supportFragmentManager para sa pamamahala ng mga fragment. Ang transaksyon na add() na may BackStack ay ginagarantiyahan na sa pagpindot ng “Bumalik” ang HomeFragment ay maibabalik. Ang openDetail() ay pinapalitan ang kasalukuyang Fragment ng DetailFragment na may mga argumento. Ang pagsusuri ng savedInstanceState == null ay pumipigil sa pagdoble ng mga fragment sa pag-ikot ng screen.
Paggamit ng Flow at StateFlow sa Fragment na may viewLifecycleOwner para sa reaktibong pag-update ng UI.
class SearchFragment : Fragment() {
private val viewModel: SearchViewModel by viewModels()
private var binding: FragmentSearchBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentSearchBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.searchButton?.setOnClickListener {
viewModel.search(binding?.queryInput?.text.toString())
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.searchResults.collectLatest { results ->
Log.d("SearchFragment", "Mga resulta ng paghahanap: ${results.size}")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
Ang Fragment ay gumagamit ng View Binding para sa pag-access sa View. Ang coroutine na viewLifecycleOwner.lifecycleScope.launch ay awtomatikong kinakansela sa pagkawasak ng View. Ang Binding ay ni-zero sa onDestroyView upang maiwasan ang pagtagas ng memorya. Ang StateFlow ay ginagarantiyahan ang pagiging napapanahon ng data sa muling paggawa ng View.
Mga madalas itanong
onCreateView — gumagawa at nagbabalik ng root View ng Fragment. onViewCreated — tinatawag kaagad pagkatapos gawin ang View, ginagarantiyahan na ang View ay ganap na nasimulan at handa na para sa pagsasaayos (findViewById, mga subscription). Inirerekomenda ng Google na sa onCreateView ay palakihin lamang ang layout, at gawin ang lahat ng pagsasaayos ng UI sa onViewCreated.
onDestroy — Ang Fragment ay nawasak bilang isang bagay (ViewModel ay nililinis, mga coroutine ay kinakansela). onDetach — huling callback, pagkatapos nito ang Fragment ay humihiwalay sa Activity. Praktikal lahat ng mapagkukunan ay dapat palayain sa onDestroyView (View) at onDestroy (Fragment). onDetach — para sa paglilinis ng mga reference sa Activity.
Nawawala ang Fragment kung hindi ito naidagdag sa FragmentManager sa pamamagitan ng transaksyon na may pag-save sa BackStack o kung hindi ibinabalik ng Activity ang FragmentManager sa onCreate. Solusyon: idagdag ang Fragment nang programmatically sa pamamagitan ng supportFragmentManager.beginTransaction().add() sa onCreate na may pagsusuri ng savedInstanceState == null.
Hindi. Ang Fragment ay laging nakatali sa Activity sa pamamagitan ng FragmentManager. Kahit sa pag-ikot ng screen, ang Activity ay ginagawang muli at ang Fragment ay muling nakakabit sa bagong Activity. Ang paggawa ng Fragment sa labas ng Activity ay imposible — ang constructor ng Fragment ay nangangailangan ng walang laman na constructor para sa pagpapanumbalik ng sistema.
Nested fragments (mga nested na fragment) — Fragment sa loob ng isa pang Fragment. Ginagamit para sa pagbuo ng mga kumplikadong screen: mga panel ng tab, mga panel na may mga tab, master-detail. Ang mga nested na fragment ay pinamamahalaan ng child FragmentManager (childFragmentManager). Inirerekomenda ng Google na huwag lumampas sa 2 antas ng nesting upang maiwasan ang mga problema sa pagganap.
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