Fragment Lifecycle — een strikt gedefinieerde reeks callback-methoden die Android aanroept tijdens de levensduur van een Fragment: van creatie (onAttach) tot volledige verwijdering (onDetach). Fragment heeft een complexere levenscyclus dan Activity — het omvat 11 toestanden en 7 belangrijke callbacks. Fragment Lifecycle wordt beheerd via FragmentManager en is nauw verbonden met de levenscyclus van de Activity die het bevat. Volgens Google wordt Fragment gebruikt in 74% van de Android-apps die draaien op API Level 21+, waardoor begrip van Fragment Lifecycle verplicht is voor professionele Android-ontwikkeling. Android-documentatie over Fragment Lifecycle beschrijft alle toestanden en aanroepgaranties.
Belangrijkste punten
Fragment Lifecycle is een set van onderling verbonden toestanden en methoden waar elke Fragment-instantie doorheen gaat van het moment van creatie tot vernietiging. In tegenstelling tot Activity is de levenscyclus van Fragment verbonden met twee contexten: het Fragment zelf (leeft van onAttach tot onDetach) en zijn View (leeft van onCreateView tot onDestroyView). Deze scheiding is een belangrijk kenmerk van Fragment, waardoor het vernietiging van de View bij schermrotatie kan overleven zonder het Fragment zelf te vernietigen.
Volledige reeks callbacks van Fragment:
Volgens Google doorloopt de gemiddelde fragment in een moderne app de volledige cyclus 3–5 keer per gebruikerssessie (vanwege schermrotaties en navigatie). Correcte verwerking van alle fasen is de basis van UI-stabiliteit.
FragmentManager beheert Fragment via vijf hoofdtoestanden, gedefinieerd in de klasse Fragment.State. Elke toestand komt overeen met een specifieke set callbacks die zijn uitgevoerd.
| Toestand | Betekenis | Uitgevoerde callbacks |
|---|---|---|
| INITIALIZED | Fragment gemaakt, maar View bestaat nog niet | onAttach, onCreate |
| CREATED | View gemaakt, maar Fragment is niet zichtbaar | + onCreateView, onViewCreated |
| STARTED | Fragment zichtbaar, maar niet actief | + onStart |
| RESUMED | Fragment actief, werkt samen met de gebruiker | + onResume |
| DESTROYED | Fragment vernietigd | + onDestroyView, onDestroy, onDetach |
FragmentManager verplaatst Fragment tussen toestanden op basis van gebruikersacties en systeemgebeurtenissen. Bij het toevoegen van Fragment aan een container doorloopt het achtereenvolgens INITIALIZED → CREATED → STARTED → RESUMED. Bij verwijdering — RESUMED → STARTED → CREATED → DESTROYED.
Toestand CREATED — bijzonder: View kan worden vernietigd (na onDestroyView), maar het Fragment zelf blijft in de toestand CREATED (na onDestroyView, vóór onDestroy). Hierdoor kan FragmentManager het Fragment in het geheugen houden zonder View, wat nodig is om schermrotaties te overleven.
Fragment Lifecycle en Activity Lifecycle zijn nauw verbonden, maar hebben fundamentele verschillen. Fragment leeft altijd binnen een Activity en zijn levenscyclus hangt af van de gastheer-Activity, maar is er niet identiek aan.
| Aspect | Activity | Fragment |
|---|---|---|
| Aantal callbacks | 7 (onCreate … onDestroy) | 11 (onAttach … onDetach) |
| Aparte Lifecycle voor View | Nee | Ja (viewLifecycleOwner) |
| Overleeft rotatie | Nee (wordt vernietigd) | Ja (ViewModel + Fragment overleven) |
| Afhankelijkheid van gastheer | Nee | Afhankelijk van Activity Lifecycle |
| Status opslaan | onSaveInstanceState | onSaveInstanceState (fragment) |
| Beheer | Systeem | FragmentManager |
Belangrijkste praktische verschil: bij schermrotatie wordt Activity volledig vernietigd (onDestroy) en opnieuw gemaakt (onCreate). Fragment doorloopt bij rotatie onDestroyView (View wordt vernietigd) → onCreateView (View wordt opnieuw gemaakt), maar het Fragment zelf en zijn ViewModel blijven leven. Dit maakt Fragment een ideale container voor UI-logica die configuratiewijzigingen moet overleven.
Aanroepvolgorde bij schermrotatie: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity vernietigd) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.
FragmentManager — de centrale klasse verantwoordelijk voor het toevoegen, verwijderen, vervangen van fragmenten en het beheren van hun toestanden. FragmentManager onderhoudt de BackStack-stack en garandeert de juiste volgorde van callbacks bij transacties. Elke Activity en elke geneste Fragment heeft zijn eigen FragmentManager.
Belangrijkste operaties van FragmentManager:
BackStack — stack van FragmentManager-transacties. Bij indrukken van de systeemknop „Terug“ wordt de laatste transactie in BackStack teruggedraaid (popBackStack()). Fragment verwijderd via popBackStack wordt hersteld. Als BackStack leeg is, beëindigt indrukken van „Terug“ de Activity.
Volgens Google is 78% van de problemen met Fragment (duplicatie, lege schermen, IllegalStateException) gerelateerd aan onjuist gebruik van FragmentManager. Hoofdregel: voer transacties uit via commit() (asynchroon) of commitNow() (synchroon) afhankelijk van de context. commit() garandeert de juiste volgorde bij meerdere transacties.
Fragment ondersteunt zijn eigen mechanisme voor statusopslag via onSaveInstanceState, dat onafhankelijk van Activity werkt. Fragment slaat status op in Bundle, die wordt doorgegeven aan onCreate en onCreateView bij herstel.
Wanneer Fragment status opslaat:
Moderne aanpak: gebruik SavedStateHandle in ViewModel voor statusopslag van Fragment. SavedStateHandle slaat automatisch gegevens op en herstelt ze bij schermrotatie en process death, zonder handmatige onSaveInstanceState. Google beveelt SavedStateHandle aan als de voorkeursmethode voor statusopslag van UI in Fragment.
setRetainInstance (verouderd sinds Fragment 1.3): voorheen kon Fragment worden behouden via setRetainInstance(true) bij schermrotatie. Deze aanpak is vervangen door ViewModel + SavedStateHandle, die betrouwbaarder werken en geen speciale configuratie vereisen.
viewLifecycleOwner — Lifecycle gekoppeld aan de View van Fragment (van onCreateView tot onDestroyView). Dit is een fundamenteel belangrijk concept: LiveData/Flow-abonnementen gemaakt via viewLifecycleOwner worden automatisch geannuleerd bij vernietiging van de View (onDestroyView), maar hebben geen invloed op het Fragment zelf.
Verschil tussen viewLifecycleOwner en lifecycle van Fragment:
Waarom dit belangrijk is: als u zich abonneert op LiveData via de lifecycle van Fragment (this), blijft het abonnement na onDestroyView actief en zal LiveData proberen de null-View bij te werken, wat NPE veroorzaakt. Abonnement via viewLifecycleOwner garandeert dat er na onDestroyView geen UI-updates plaatsvinden.
Regel: gebruik in Fragment altijd viewLifecycleOwner voor abonnementen op LiveData, Flow en coroutines die verband houden met UI. Gebruik voor ViewModel-coroutines viewModelScope — deze is gekoppeld aan ViewModel, niet aan Fragment.
Demonstreert correcte initialisatie van UI en LiveData-abonnement via 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", "Lijst bijwerken: ${users.size} gebruikers")
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("UserListFragment", "onDestroyView: View vernietigd")
}
}
Fragment blaast de layout op in onCreateView, configureert UI en abonneert zich op LiveData in onViewCreated. Abonnement via viewLifecycleOwner — een verplichte vereiste om geheugenlekken te voorkomen. onDestroyView logt de vernietiging van View — bevestiging dat Fragment schermrotatie overleeft.
Demonstreert het toevoegen van Fragment via FragmentManager in Activity, vervanging met BackStack en herstel.
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", "Gebruikersdetails laden: $userId")
}
}
Activity gebruikt supportFragmentManager voor het beheren van fragmenten. De transactie add() met BackStack garandeert dat HomeFragment wordt hersteld bij indrukken van „Terug“. openDetail() vervangt het huidige Fragment door DetailFragment met argumenten. Controle savedInstanceState == null voorkomt duplicatie van fragmenten bij schermrotatie.
Gebruik van Flow en StateFlow in Fragment met viewLifecycleOwner voor reactieve UI-updates.
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", "Zoekresultaten: ${results.size}")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
Fragment gebruikt View Binding voor toegang tot View. De coroutine viewLifecycleOwner.lifecycleScope.launch wordt automatisch geannuleerd bij vernietiging van View. Binding wordt op nul gezet in onDestroyView om geheugenlekken te voorkomen. StateFlow garandeert actualiteit van gegevens bij het opnieuw maken van de View.
Veelgestelde vragen
onCreateView — maakt en retourneert de root-View van Fragment. onViewCreated — wordt direct na het maken van de View aangeroepen, garandeert dat de View volledig is geïnitialiseerd en klaar is voor configuratie (findViewById, abonnementen). Google raadt aan om in onCreateView alleen de layout op te blazen en alle UI-configuratie in onViewCreated te doen.
onDestroy — Fragment is vernietigd als object (ViewModel wordt opgeschoond, coroutines geannuleerd). onDetach — laatste callback, waarna Fragment losgekoppeld wordt van Activity. Praktisch alle bronnen moeten worden vrijgemaakt in onDestroyView (View) en onDestroy (Fragment). onDetach — voor het opschonen van verwijzingen naar Activity.
Fragment verdwijnt als het niet via een transactie met behoud in BackStack aan FragmentManager is toegevoegd of als Activity FragmentManager niet herstelt in onCreate. Oplossing: voeg Fragment programmatisch toe via supportFragmentManager.beginTransaction().add() in onCreate met controle van savedInstanceState == null.
Nee. Fragment is altijd gekoppeld aan een Activity via FragmentManager. Zelfs bij schermrotatie wordt Activity opnieuw gemaakt en wordt Fragment opnieuw aan de nieuwe Activity gekoppeld. Het maken van een Fragment buiten een Activity is onmogelijk — de constructor van Fragment vereist een lege constructor voor herstel door het systeem.
Nested fragments (geneste fragmenten) — Fragment binnen een ander Fragment. Worden gebruikt voor het bouwen van complexe schermen: tab-panelen, paneel met tabbladen, master-detail. Geneste fragmenten worden beheerd door de onderliggende FragmentManager (childFragmentManager). Google raadt aan om niet meer dan 2 niveaus van nesting te gebruiken om prestatieproblemen te voorkomen.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook