Fragment Lifecycle: bazele, metodele onCreateView onViewCreated

Autor: IT Sectr Publicat: 2026-03-04 Timp de citire: 12 min

Fragment Lifecycle — o secvență strict definită de metode de tip callback pe care Android le apelează pe durata de viață a unui Fragment: de la creare (onAttach) până la ștergerea completă (onDetach). Fragment are un ciclu de viață mai complex decât Activity — include 11 stări și 7 callback-uri principale. Fragment Lifecycle este gestionat prin FragmentManager și este strâns legat de ciclul de viață al Activity-ului care îl conține. Conform datelor Google, Fragment este utilizat în 74% din aplicațiile Android care rulează pe API Level 21+, ceea ce face înțelegerea Fragment Lifecycle obligatorie pentru dezvoltarea profesională Android. Documentația Android despre Fragment Lifecycle descrie toate stările și garanțiile de apelare.

Principalele puncte

  • Fragment Lifecycle include 7 callback-uri: onAttach, onCreate, onCreateView, onViewCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach.
  • FragmentManager gestionează stările Fragment și garantează ordinea corectă a apelurilor în tranzacții.
  • onCreateView și onViewCreated — metode cheie pentru crearea și configurarea UI-ului Fragment.
  • Fragment poate supraviețui Activity-ului său (la rotirea ecranului) și poate restabili starea prin onSaveInstanceState.
  • viewLifecycleOwner — un Lifecycle separat pentru View-ul Fragment, distrus în onDestroyView.

Fragment Lifecycle: bazele ciclului de viață

Fragment Lifecycle este un set de stări și metode interconectate prin care trece fiecare instanță Fragment de la momentul creării până la distrugere. Spre deosebire de Activity, ciclul de viață al Fragment este legat de două contexte: Fragmentul însuși (trăiește de la onAttach până la onDetach) și View-ul său (trăiește de la onCreateView până la onDestroyView). Această separare este o caracteristică cheie a Fragment, permițând supraviețuirea distrugerii View-ului la rotirea ecranului fără a distruge Fragmentul însuși.

Secvența completă a callback-urilor Fragment:

  • onAttach(Context) — Fragment se atașează la Activity. Se apelează primul. Context — Activity-ul gazdă.
  • onCreate(Bundle) — Fragment este inițializat. Aici sunt create ViewModel-uri, configurate adaptoare.
  • onCreateView(LayoutInflater, ViewGroup, Bundle) — se creează ierarhia View-urilor Fragment. Returnează View-ul rădăcină.
  • onViewCreated(View, Bundle) — View-ul a fost creat. Aici se configurează elementele UI, abonamentele LiveData.
  • onStart() — Fragment este vizibil. Se pornesc animațiile, se înregistrează senzorii.
  • onResume() — Fragment este activ, interacționează cu utilizatorul.
  • onPause() — Fragment pierde focalizarea. Se opresc animațiile.
  • onStop() — Fragment este invizibil. Se eliberează resursele necritice.
  • onDestroyView() — ierarhia View-urilor este distrusă. Referințele către View sunt anulate.
  • onDestroy() — Fragment este distrus. Corutinele care nu sunt în viewModelScope sunt anulate.
  • onDetach() — Fragment se deconectează de la Activity. Curățarea finală.

Conform Google, fragmentul mediu într-o aplicație modernă parcurge ciclul complet de 3–5 ori pe sesiune de utilizator (din cauza rotirilor de ecran și a navigației). Gestionarea corectă a tuturor fazelor este baza stabilității UI.

Stările Fragment: de la INITIALIZED la DESTROYED

FragmentManager gestionează Fragment prin cinci stări principale, definite în clasa Fragment.State. Fiecare stare corespunde unui set specific de callback-uri care au fost executate.

StareSemnificațieCallback-uri executate
INITIALIZEDFragment creat, dar View încă nu existăonAttach, onCreate
CREATEDView creat, dar Fragment nu este vizibil+ onCreateView, onViewCreated
STARTEDFragment vizibil, dar inactiv+ onStart
RESUMEDFragment activ, interacționează cu utilizatorul+ onResume
DESTROYEDFragment distrus+ onDestroyView, onDestroy, onDetach

FragmentManager mută Fragment între stări în funcție de acțiunile utilizatorului și evenimentele sistemului. La adăugarea Fragment într-un container, acesta trece succesiv prin INITIALIZED → CREATED → STARTED → RESUMED. La ștergere — RESUMED → STARTED → CREATED → DESTROYED.

Starea CREATED — specială: View-ul poate fi distrus (după onDestroyView), dar Fragmentul însuși rămâne în starea CREATED (după onDestroyView, înainte de onDestroy). Acest lucru permite FragmentManager să păstreze Fragment în memorie fără View, ceea ce este necesar pentru supraviețuirea rotirilor de ecran.

Diferența dintre Fragment Lifecycle și Activity Lifecycle

Fragment Lifecycle și Activity Lifecycle sunt strâns legate, dar au diferențe fundamentale. Fragment trăiește întotdeauna în interiorul unui Activity, iar ciclul său de viață depinde de Activity-ul gazdă, dar nu este identic cu acesta.

AspectActivityFragment
Număr de callback-uri7 (onCreate … onDestroy)11 (onAttach … onDetach)
Lifecycle separat pentru ViewNuDa (viewLifecycleOwner)
Supraviețuiește rotiriiNu (se distruge)Da (ViewModel + Fragment supraviețuiesc)
Dependența de gazdăNuDepinde de Activity Lifecycle
Salvarea stăriionSaveInstanceStateonSaveInstanceState (fragment)
GestionareSistemFragmentManager

Principala diferență practică: la rotirea ecranului, Activity este distrus complet (onDestroy) și recreat (onCreate). Fragment la rotire trece prin onDestroyView (View-ul este distrus) → onCreateView (View-ul este recreat), dar Fragmentul însuși și ViewModel-ul său rămân vii. Acest lucru face din Fragment un container ideal pentru logica UI care trebuie să supraviețuiască modificărilor de configurare.

Ordinea apelurilor la rotirea ecranului: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity distrusă) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.

FragmentManager: gestionarea stărilor și tranzacțiilor

FragmentManager — clasa centrală responsabilă pentru adăugarea, ștergerea, înlocuirea fragmentelor și gestionarea stărilor acestora. FragmentManager menține stiva BackStack și garantează ordinea corectă a callback-urilor în tranzacții. Fiecare Activity și fiecare Fragment imbricat au propriul FragmentManager.

Operațiile principale ale FragmentManager:

  • beginTransaction() — deschide o tranzacție pentru un grup de operații.
  • add() — adaugă Fragment într-un container. Fragment parcurge lifecycle-ul complet până la RESUMED.
  • replace() — înlocuiește Fragmentul curent cu unul nou. echivalează cu remove() + add().
  • remove() — șterge Fragment. Fragment parcurge lifecycle-ul de la RESUMED la DESTROYED.
  • hide()/show() — ascunde/afișează Fragment fără a distruge View-ul. Fragment trece în STARTED la hide, înapoi în RESUMED la show.
  • detach()/attach() — detașează/atașează Fragment. detach distruge View-ul (onDestroyView), attach îl creează din nou (onCreateView).
  • addToBackStack() — adaugă tranzacția în BackStack pentru posibilitatea navigării „Înapoi“.

BackStack — stiva tranzacțiilor FragmentManager. La apăsarea butonului de sistem „Înapoi“, ultima tranzacție din BackStack este anulată (popBackStack()). Fragmentul șters prin popBackStack este restaurat. Dacă BackStack este gol, apăsarea „Înapoi“ finalizează Activity.

Conform Google, 78% dintre problemele cu Fragment (duplicare, ecrane goale, IllegalStateException) sunt legate de utilizarea incorectă a FragmentManager. Regula principală: executați tranzacțiile prin commit() (asincron) sau commitNow() (sincron) în funcție de context. commit() garantează ordinea corectă în cazul tranzacțiilor multiple.

Salvarea stării Fragment: onSaveInstanceState

Fragment suportă propriul mecanism de salvare a stării prin onSaveInstanceState, care funcționează independent de Activity. Fragment salvează starea în Bundle, care este transmis în onCreate și onCreateView la restaurare.

Când Fragment își salvează starea:

  • La rotirea ecranului — View-ul este distrus, Fragment salvează starea în Bundle.
  • La atașarea Fragment la Activity după process death.
  • La apelarea onSaveInstanceState din Activity (sistemul propagă salvarea la toate fragmentele copil).

Abordarea modernă: utilizați SavedStateHandle în ViewModel pentru salvarea stării Fragment. SavedStateHandle salvează și restaurează automat datele la rotirea ecranului și process death, fără a necesita onSaveInstanceState manual. Google recomandă SavedStateHandle ca metodă preferată de salvare a stării UI în Fragment.

setRetainInstance (învechit din Fragment 1.3): anterior Fragment putea fi păstrat prin setRetainInstance(true) la rotirea ecranului. Această abordare a fost înlocuită cu ViewModel + SavedStateHandle, care funcționează mai fiabil și nu necesită configurare specială.

viewLifecycleOwner: ciclul de viață separat al View-ului

viewLifecycleOwner — Lifecycle atașat View-ului Fragment (de la onCreateView până la onDestroyView). Acesta este un concept fundamental important: abonamentele LiveData/Flow făcute prin viewLifecycleOwner sunt anulate automat la distrugerea View-ului (onDestroyView), dar nu afectează Fragmentul însuși.

Diferența dintre viewLifecycleOwner și lifecycle-ul Fragment:

  • lifecycle (Fragment) — trăiește de la onAttach până la onDetach. Abonamentele rămân active chiar și după distrugerea View-ului.
  • viewLifecycleOwner — trăiește de la onCreateView până la onDestroyView. Abonamentele sunt anulate la distrugerea View-ului.

De ce este important: dacă vă abonați la LiveData prin lifecycle-ul Fragment (this), după onDestroyView abonamentul rămâne activ și LiveData va încerca să actualizeze View-ul null, provocând NPE. Abonamentul prin viewLifecycleOwner garantează că după onDestroyView nu vor avea loc actualizări UI.

Regula: în Fragment, utilizați întotdeauna viewLifecycleOwner pentru abonamentele la LiveData, Flow și corutinele legate de UI. Pentru corutinele ViewModel, utilizați viewModelScope — acesta este atașat de ViewModel, nu de Fragment.

Exemple de cod Fragment în Kotlin

Exemplul 1: Fragment de bază cu onViewCreated și viewLifecycleOwner

Demonstrează inițializarea corectă a UI și abonamentul LiveData prin viewLifecycleOwner.

kotlin
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", "Actualizare listă: ${users.size} utilizatori")
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Log.d("UserListFragment", "onDestroyView: View distrus")
    }
}

Fragment umflă layout-ul în onCreateView, configurează UI și se abonează la LiveData în onViewCreated. Abonamentul prin viewLifecycleOwner — o cerință obligatorie pentru prevenirea scurgerilor de memorie. onDestroyView înregistrează distrugerea View-ului — confirmare că Fragment supraviețuiește rotirii ecranului.

Exemplul 2: Fragment cu FragmentManager și tranzacții

Demonstrează adăugarea Fragment prin FragmentManager în Activity, înlocuirea cu BackStack și restaurarea.

kotlin
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", "Încărcare detalii utilizator: $userId")
    }
}

Activity folosește supportFragmentManager pentru gestionarea fragmentelor. Tranzacția add() cu BackStack garantează că la apăsarea „Înapoi“ HomeFragment va fi restaurat. openDetail() înlocuiește Fragmentul curent cu DetailFragment cu argumente. Verificarea savedInstanceState == null previne duplicarea fragmentelor la rotirea ecranului.

Exemplul 3: Fragment cu LifecycleObserver și StateFlow

Utilizarea Flow și StateFlow în Fragment cu viewLifecycleOwner pentru actualizarea reactivă a UI.

kotlin
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", "Rezultate căutare: ${results.size}")
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
    }
}

Fragment folosește View Binding pentru accesul la View. Corutina viewLifecycleOwner.lifecycleScope.launch este anulată automat la distrugerea View-ului. Binding este anulat în onDestroyView pentru prevenirea scurgerilor de memorie. StateFlow garantează actualitatea datelor la recrearea View-ului.

Întrebări frecvente

Cu ce se deosebește onViewCreated de onCreateView?

onCreateView — creează și returnează View-ul rădăcină al Fragment. onViewCreated — este apelat imediat după crearea View-ului, garantează că View-ul este complet inițializat și gata de configurare (findViewById, abonamente). Google recomandă ca în onCreateView să umflați doar layout-ul, iar toată configurarea UI să o faceți în onViewCreated.

Când este distrus Fragment cu adevărat — onDestroy sau onDetach?

onDestroy — Fragment este distrus ca obiect (ViewModel este curățat, corutinele anulate). onDetach — ultimul callback, după care Fragment se deconectează de la Activity. Practic, toate resursele trebuie eliberate în onDestroyView (View) și onDestroy (Fragment). onDetach — pentru curățarea referințelor către Activity.

De ce dispare Fragment după rotirea ecranului?

Fragment dispare dacă nu a fost adăugat în FragmentManager printr-o tranzacție cu păstrarea în BackStack sau dacă Activity nu restaurează FragmentManager în onCreate. Soluție: adăugați Fragment programatic prin supportFragmentManager.beginTransaction().add() în onCreate cu verificarea savedInstanceState == null.

Poate exista un Fragment fără Activity?

Nu. Fragment este întotdeauna atașat de un Activity prin FragmentManager. Chiar și la rotirea ecranului, Activity este recreat, iar Fragment este reatașat la noul Activity. Crearea unui Fragment în afara Activity este imposibilă — constructorul Fragment necesită un constructor gol pentru restaurarea de către sistem.

Ce sunt nested fragments și la ce servesc?

Nested fragments (fragmente imbricate) — Fragment în interiorul altui Fragment. Sunt utilizate pentru construirea ecranelor complexe: panouri cu file, panouri cu tab-uri, master-detail. Fragmentele imbricate sunt gestionate de FragmentManager-ul copil (childFragmentManager). Google recomandă să nu depășiți 2 niveluri de imbricare pentru a evita problemele de performanță.

Rezumat

  • Fragment Lifecycle include 11 callback-uri: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume → onPause → onStop → onDestroyView → onDestroy → onDetach.
  • FragmentManager gestionează stările Fragment (INITIALIZED → CREATED → STARTED → RESUMED → DESTROYED) și BackStack-ul tranzacțiilor.
  • Fragment supraviețuiește rotirii ecranului — View-ul este distrus (onDestroyView), dar Fragment și ViewModel rămân vii.
  • viewLifecycleOwner — Lifecycle separat pentru View-ul Fragment; obligatoriu pentru abonamente LiveData și corutine UI.
  • Salvarea stării Fragment — prin onSaveInstanceState sau SavedStateHandle în ViewModel.
  • Tranzacțiile Fragment se execută prin FragmentManager cu commit() (asincron) sau commitNow() (sincron).
  • Întotdeauna anulați binding-ul și referințele către View în onDestroyView pentru prevenirea scurgerilor de memorie.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și