Fragment Lifecycle — a callback metódusok szigorúan meghatározott sorozata, amelyeket az Android a Fragment élete során meghív: a létrehozástól (onAttach) a teljes eltávolításig (onDetach). A Fragment bonyolultabb életciklussal rendelkezik, mint az Activity — 11 állapotot és 7 alapvető callback-et foglal magában. A Fragment Lifecycle-t a FragmentManager kezeli, és szorosan kapcsolódik az azt tartalmazó Activity életciklusához. A Google adatai szerint a Fragment az API Level 21+ rendszeren futó Android-alkalmazások 74%-ában használatos, ami a Fragment Lifecycle megértését kötelezővé teszi a professzionális Android-fejlesztéshez. Az Android Fragment Lifecycle-ről szóló dokumentációja leírja az összes állapotot és a meghívás garanciáit.
Főbb pontok
Fragment Lifecycle az egymással összefüggő állapotok és metódusok halmaza, amelyen minden Fragment-példány áthalad a létrehozástól a megsemmisülésig. Az Activity-től eltérően a Fragment életciklusa két kontextushoz kötődik: magához a Fragmenthez (onAttach-tól onDetach-ig él) és a View-jához (onCreateView-tól onDestroyView-ig él). Ez a szétválasztás a Fragment kulcsfontosságú jellemzője, amely lehetővé teszi a View megsemmisülésének túlélését képernyőelforgatáskor anélkül, hogy maga a Fragment megsemmisülne.
A Fragment callback-ek teljes sorozata:
A Google szerint az átlagos fragmentum egy modern alkalmazásban 3–5 alkalommal megy át a teljes cikluson felhasználói munkamenetenként (a képernyőelforgatások és navigáció miatt). Az összes fázis helyes kezelése az UI stabilitásának alapja.
A FragmentManager öt fő állapoton keresztül kezeli a Fragmentet, amelyek a Fragment.State osztályban vannak meghatározva. Minden állapot a végrehajtott callback-ek egy meghatározott készletének felel meg.
| Állapot | Jelentés | Végrehajtott callback-ek |
|---|---|---|
| INITIALIZED | Fragment létrejött, de View még nincs | onAttach, onCreate |
| CREATED | View létrejött, de Fragment nem látható | + onCreateView, onViewCreated |
| STARTED | Fragment látható, de nem aktív | + onStart |
| RESUMED | Fragment aktív, kapcsolatba lép a felhasználóval | + onResume |
| DESTROYED | Fragment megsemmisült | + onDestroyView, onDestroy, onDetach |
A FragmentManager a Fragmentet a felhasználói műveletektől és rendszereseményektől függően mozgatja az állapotok között. Amikor egy Fragmentet hozzáadnak egy konténerhez, egymás után INITIALIZED → CREATED → STARTED → RESUMED állapotokon megy keresztül. Eltávolításkor — RESUMED → STARTED → CREATED → DESTROYED.
A CREATED állapot — különleges: a View megsemmisülhet (onDestroyView után), de maga a Fragment a CREATED állapotban marad (onDestroyView után, onDestroy előtt). Ez lehetővé teszi a FragmentManager számára, hogy a Fragmentet View nélkül tartsa a memóriában, ami szükséges a képernyőelforgatások túléléséhez.
A Fragment Lifecycle és az Activity Lifecycle szorosan kapcsolódnak, de alapvető különbségek vannak közöttük. A Fragment mindig egy Activity-n belül él, és életciklusa a gazda-Activity-től függ, de nem azonos azzal.
| Szempont | Activity | Fragment |
|---|---|---|
| Callback-ek száma | 7 (onCreate … onDestroy) | 11 (onAttach … onDetach) |
| Külön Lifecycle a View-hoz | Nem | Igen (viewLifecycleOwner) |
| Túlél forgatást | Nem (megsemmisül) | Igen (ViewModel + Fragment túlél) |
| Gazdától függés | Nem | Függ az Activity Lifecycle-től |
| Állapot mentése | onSaveInstanceState | onSaveInstanceState (fragmentum) |
| Kezelés | Rendszer | FragmentManager |
A fő gyakorlati különbség: képernyőelforgatáskor az Activity teljesen megsemmisül (onDestroy) és újra létrejön (onCreate). A Fragment forgatáskor az onDestroyView (View megsemmisül) → onCreateView (View újra létrejön) útvonalon halad, de maga a Fragment és ViewModel-je életben marad. Ez teszi a Fragmentet ideális tárolóvá az olyan UI-logika számára, amelynek túl kell élnie a konfigurációs változásokat.
Hívások sorrendje képernyőelforgatáskor: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity megsemmisült) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.
FragmentManager — a központi osztály, amely felelős a fragmentumok hozzáadásáért, eltávolításáért, cseréjéért és állapotuk kezeléséért. A FragmentManager a BackStack vermet kezeli és garantálja a callback-ek helyes sorrendjét a tranzakciókban. Minden Activity és minden beágyazott Fragment saját FragmentManager-rel rendelkezik.
A FragmentManager fő műveletei:
BackStack — a FragmentManager tranzakcióinak verme. A rendszer „Vissza“ gombjának megnyomásakor a BackStack utolsó tranzakciója visszavonásra kerül (popBackStack()). A popBackStack által eltávolított Fragment helyreáll. Ha a BackStack üres, a „Vissza“ gomb megnyomása befejezi az Activity-t.
A Google szerint a Fragment problémák 78%-a (duplikáció, üres képernyők, IllegalStateException) a FragmentManager helytelen használatához kapcsolódik. Fő szabály: a tranzakciókat a commit() (aszinkron) vagy commitNow() (szinkron) segítségével hajtsa végre a kontextustól függően. A commit() garantálja a helyes sorrendet többszörös tranzakciók esetén.
A Fragment támogatja saját állapotmentési mechanizmusát az onSaveInstanceState segítségével, amely az Activity-től függetlenül működik. A Fragment az állapotot Bundle-ben menti, amely a visszaállításkor az onCreate és onCreateView metódusokba kerül továbbításra.
Mikor menti a Fragment az állapotot:
Modern megközelítés: használja a SavedStateHandle-t a ViewModel-ben a Fragment állapotának mentéséhez. A SavedStateHandle automatikusan menti és visszaállítja az adatokat képernyőelforgatáskor és process death esetén, anélkül hogy kézi onSaveInstanceState-ra lenne szükség. A Google a SavedStateHandle-t ajánlja az UI állapotának mentésére a Fragment-ben.
setRetainInstance (elavult a Fragment 1.3 óta): korábban a Fragment megőrizhető volt a setRetainInstance(true) segítségével képernyőelforgatáskor. Ezt a megközelítést felváltotta a ViewModel + SavedStateHandle, amelyek megbízhatóbban működnek és nem igényelnek különleges konfigurációt.
viewLifecycleOwner — a Fragment View-jához kapcsolódó Lifecycle (onCreateView-től onDestroyView-ig). Ez egy alapvetően fontos koncepció: a viewLifecycleOwner segítségével létrehozott LiveData/Flow feliratkozások automatikusan törlődnek a View megsemmisülésekor (onDestroyView), de nem érintik magát a Fragmentet.
Különbség a viewLifecycleOwner és a Fragment lifecycle között:
Miért fontos ez: ha a LiveData-ra a Fragment lifecycle (this) segítségével fizet fel, az onDestroyView után a feliratkozás aktív marad, és a LiveData megpróbálja frissíteni a null View-t, NPE-t okozva. A viewLifecycleOwner segítségével történő feliratkozás garantálja, hogy onDestroyView után nem történik UI-frissítés.
Szabály: Fragment-ben mindig a viewLifecycleOwner-t használja az UI-hoz kapcsolódó LiveData, Flow és korutin feliratkozásokhoz. A ViewModel korutinjaihoz a viewModelScope-ot használja — ez a ViewModel-hez kapcsolódik, nem a Fragmenthez.
Bemutatja az UI helyes inicializálását és a LiveData feliratkozást a viewLifecycleOwner segítségével.
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", "Lista frissítése: ${users.size} felhasználó")
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("UserListFragment", "onDestroyView: View megsemmisült")
}
}
A Fragment az onCreateView-ben felfújja a layout-ot, konfigurálja az UI-t és feliratkozik a LiveData-ra az onViewCreated-ben. A viewLifecycleOwner segítségével történő feliratkozás — kötelező követelmény a memóriaszivárgás megelőzéséhez. Az onDestroyView naplózza a View megsemmisülését — megerősítés, hogy a Fragment túléli a képernyőelforgatást.
Bemutatja a Fragment hozzáadását a FragmentManager segítségével az Activity-ben, a BackStack-es cserét és a visszaállítást.
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", "Felhasználói adatok betöltése: $userId")
}
}
Az Activity a supportFragmentManager-t használja a fragmentumok kezeléséhez. Az add() tranzakció BackStack-el garantálja, hogy a „Vissza“ gomb megnyomásakor a HomeFragment helyreáll. Az openDetail() lecseréli az aktuális Fragmentet DetailFragment-re argumentumokkal. A savedInstanceState == null ellenőrzés megakadályozza a fragmentumok duplikálódását képernyőelforgatáskor.
A Flow és StateFlow használata Fragment-ben viewLifecycleOwner segítségével az UI reaktív frissítéséhez.
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", "Keresési eredmények: ${results.size}")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
A Fragment View Binding-et használ a View eléréséhez. A viewLifecycleOwner.lifecycleScope.launch korutin automatikusan törlődik a View megsemmisülésekor. A Binding nullázódik az onDestroyView-ben a memóriaszivárgás megelőzése érdekében. A StateFlow garantálja az adatok időszerűségét a View újralétrehozásakor.
Gyakran ismételt kérdések
onCreateView — létrehozza és visszaadja a Fragment gyökér View-ját. onViewCreated — közvetlenül a View létrehozása után hívódik meg, garantálja, hogy a View teljesen inicializált és készen áll a konfigurációra (findViewById, feliratkozások). A Google azt ajánlja, hogy az onCreateView-ben csak a layout-ot fújja fel, az összes UI-konfigurációt pedig az onViewCreated-ben végezze.
onDestroy — a Fragment objektumként megsemmisült (ViewModel törlődik, korutinok törlődnek). onDetach — az utolsó callback, amely után a Fragment leválik az Activity-ről. Gyakorlatilag az összes erőforrást az onDestroyView-ben (View) és onDestroy-ben (Fragment) kell felszabadítani. onDetach — az Activity-re mutató referenciák tisztításához.
A Fragment eltűnik, ha nem a BackStack-ben való megőrzéssel történő tranzakcióval adták hozzá a FragmentManager-hez, vagy ha az Activity nem állítja vissza a FragmentManager-t az onCreate-ben. Megoldás: adja hozzá a Fragmentet programozottan a supportFragmentManager.beginTransaction().add() segítségével az onCreate-ben, a savedInstanceState == null ellenőrzéssel.
Nem. A Fragment mindig egy Activity-hez kapcsolódik a FragmentManager-en keresztül. Még képernyőelforgatáskor is az Activity újra létrejön, és a Fragment újracsatolódik az új Activity-hez. Fragment létrehozása Activity-n kívül lehetetlen — a Fragment konstruktora üres konstruktort igényel a rendszer általi visszaállításhoz.
Nested fragments (beágyazott fragmentumok) — Fragment egy másik Fragment-en belül. Összetett képernyők építésére használják: lap panelek, füles panelek, master-detail. A beágyazott fragmentumokat a gyermek FragmentManager (childFragmentManager) kezeli. A Google azt ajánlja, hogy ne lépje túl a 2 szintű beágyazást a teljesítményproblémák elkerülése érdekében.
Összegzés
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is