onDestroy: ce este, finalizarea Activity în Android

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

onDestroy — metoda finală a ciclului de viață al Activity și Fragment în Android, apelată înainte de distrugerea completă a componentului. onDestroy semnalează că Activity sau Fragment își încheie activitatea: toate resursele trebuie eliberate, fragmentele imbricate — distruse, ViewModel — curățat. Conform datelor Google, onDestroy este apelat în 100% din cazurile de finalizare a Activity, dar la uciderea procesului (process death) sistemul poate omite complet apelul onDestroy. Documentația Android despre onDestroy subliniază că această metodă nu garantează apelul la finalizarea accidentală.

Principalele

  • onDestroy — ultimul apel înainte de distrugerea Activity sau Fragment, destinat curățării finale a resurselor.
  • Apelul onDestroy nu este garantat la uciderea procesului de către sistem (process death) — nu vă bazați pe el pentru salvarea datelor critice.
  • În onDestroy trebuie anulate sarcinile de fundal, închise socket-urile și bazele de date, curățat ViewModelStore.
  • Diferența față de onStop: onStop — pierderea vizibilității (Activity trăiește în memorie), onDestroy — distrugerea completă.
  • isFinishing() în onDestroy arată dacă Activity se finalizează la comanda utilizatorului (finish()) sau la decizia sistemului.

onDestroy: ce este în Android?

onDestroy — o metodă de apel invers pe care Android o apelează înainte de a distruge definitiv Activity sau Fragment. Aceasta este ultima șansă pentru dezvoltator de a elibera resurse, de a anula operațiile de fundal și de a finaliza lucrul cu datele. După executarea onDestroy, instanța Activity/Fragment este marcată pentru colectarea gunoiului (GC) și nu mai poate fi utilizată.

Cauzele apelării onDestroy:

  • Apelul explicit finish() — utilizatorul a apăsat „Înapoi” sau dezvoltatorul a apelat finishActivity().
  • Rotirea ecranului — Activity este distrus și recreat cu o nouă configurație.
  • Schimbarea configurației — tastatură, schimbare limbă, modificarea dimensiunii ecranului (multi-window).
  • Decizia sistemului — Android ucide Activity pentru eliberarea resurselor (dar onDestroy poate să nu fie apelat).

Conform statisticilor Google Android Vitals (2025), aproximativ 12% din toate cazurile de distrugere a Activity se datorează rotirii ecranului, 65% — finish() și 23% — schimbării configurației. Procentul uciderilor de procese cu omiterea onDestroy este de aproximativ 5–8% în funcție de dispozitivele cu RAM mică (sub 4 GB).

Când onDestroy este apelat — și când nu este apelat

onDestroy este apelat în majoritatea scenariilor standard, dar există excepții importante pe care dezvoltatorul trebuie să le ia în considerare. Înțelegerea garanțiilor de apelare a onDestroy este critică pentru arhitectura aplicației, în special pentru salvarea datelor și anularea sarcinilor WorkManager.

Când onDestroy este apelat:

  • Utilizatorul apasă butonul „Înapoi” — Activity.finish() → onPause → onStop → onDestroy.
  • Rotirea ecranului — Activity este distrus (onPause → onStop → onDestroy), apoi recreat.
  • Schimbarea configurației — setare de sistem care necesită recrearea Activity.
  • Apelarea finishAffinity() — finalizarea tuturor Activity din stivă.
  • Ștergerea Fragment din FragmentManager — Fragment primește onPause → onStop → onDestroyView → onDestroy → onDetach.

Când onDestroy NU este apelat:

  • Uciderea procesului de către sistem (process death) — Android ucide întregul proces al aplicației la lipsa de memorie. Activity nu primește onDestroy, deoarece procesul se termină la nivelul nucleului Linux.
  • Finalizarea accidentală — o excepție neprinsă în thread-ul principal ucide aplicația fără apelarea onDestroy.
  • Force Stop — utilizatorul oprește forțat aplicația în setări.

Din cauza lipsei garanției de apelare a onDestroy, Google recomandă: nu vă bazați niciodată pe onDestroy pentru salvarea datelor critice. Folosiți onSaveInstanceState(), WorkManager sau Room cu salvare automată. onDestroy — pentru eliberarea resurselor, nu pentru persistență.

onDestroy în Activity și Fragment: asemănări și diferențe

onDestroy există atât pentru Activity, cât și pentru Fragment, dar cu contracte diferite. La Fragment, ciclul de viață este mai detaliat: pe lângă onDestroy există onDestroyView (distrugerea ierarhiei View) și onDetach (deconectarea de la Activity).

ComponentMetode de distrugereOrdineaViewModel supraviețuiește
ActivityonDestroyonPause → onStop → onDestroyNu (doar dacă ViewModelStore nu este salvat)
FragmentonDestroyView, onDestroy, onDetachonPause → onStop → onDestroyView → onDestroy → onDetachDa, dacă Fragment nu este șters

Diferența cheie: la Fragment, View este recreat mai des decât Fragmentul însuși. La rotirea ecranului, Fragment trece prin onDestroyView (distrugerea View), dar Fragmentul însuși și ViewModel-ul său rămân vii. onDestroyView — locul potrivit pentru curățarea referințelor la View pentru a evita scurgerile de memorie. onDestroy Fragment — analogul onDestroy Activity, apelat la ștergerea completă a Fragmentului.

Fragmentele imbricate (child fragments) sunt distruse înainte de onDestroy al Fragmentului părinte. În Activity, fragmentele copil primesc onDestroy la apelarea onDestroy al Activity părinte. Ordinea este garantată: fragmentele se termină mai devreme decât Activity care le conține.

Ce să faceți în onDestroy: lista de verificare a curățării

onDestroy este destinat eliberării tuturor resurselor care nu ar trebui să trăiască mai mult decât Activity sau Fragment. Spre deosebire de onStop, care eliberează resursele până la revenire, onDestroy efectuează curățarea finală.

Lista de verificare a acțiunilor obligatorii în onDestroy:

  • Anularea corutinelor și Flow — anulați job-urile care nu sunt legate de viewModelScope. viewModelScope se anulează automat, dar lifecycleScope este legat de ciclul de viață al Activity.
  • Închiderea socket-urilor și canalelor — WebSocket (OkHttp), BluetoothSocket, ServerSocket. A le ține deschise după distrugere este o scurgere de resurse de sistem.
  • Închiderea fișierelor și fluxurilor — FileInputStream, FileOutputStream, Cursor. Cursor poate provoca ANR pe ContentProvider dacă nu este închis.
  • Dezabonarea de la ContentObserver — dacă Activity urmărește modificările de conținut (contacte, mediatecă).
  • Dezabonarea de la BroadcastReceiver — receiver-ele înregistrate dinamic trebuie anulate.
  • Închiderea bazei de date — Room închide conexiunea automat la distrugerea Application, dar SQLiteDatabase direct necesită close() manual.

Ce să NU faceți în onDestroy: Nu salvați datele în onDestroy — folosiți onPause sau onSaveInstanceState. Nu lansați Service sau sarcini WorkManager noi — Activity va fi distrus și nu veți putea urmări rezultatul. Nu încercați să actualizați UI — ierarhia View este deja distrusă sau în curs de distrugere; apelarea findViewById() va returna null.

onDestroy și ViewModel: colaborare

ViewModel este proiectat să supraviețuiască onDestroy Activity la rotirea ecranului, dar să fie distrus împreună cu Activity la finish(). Acest comportament asimetric — principala cauză de confuzie printre dezvoltatori.

La rotirea ecranului:

  • Activity: onPause → onStop → onDestroy (Activity distrus).
  • ViewModel: NEDISTRUS — ViewModelStore este salvat și transmis noului Activity.
  • Activity nou: onCreate → onStart → onResume, primește același ViewModel.

La finish() (utilizatorul a apăsat „Înapoi”):

  • Activity: onPause → onStop → onDestroy.
  • ViewModel: onCleared() — apelat după onDestroy Activity.
  • Toate corutinele viewModelScope sunt anulate automat.

Prin urmare, anularea viewModelScope în onDestroy nu este necesară — ViewModel o va face singur. Dacă utilizați lifecycleScope (legat de Activity, nu de ViewModel), anulați-l în onDestroy prin lifecycleScope.cancel() sau gestionați Job manual.

Exemple de cod cu onDestroy în Kotlin

Exemplul 1: onDestroy Activity cu anularea corutinei lifecycleScope

Demonstrează gestionarea corectă a lifecycleScope în Activity: corutina este lansată pentru urmărirea stării rețelei și anulată în onDestroy.

kotlin
class NetworkMonitorActivity : AppCompatActivity() {
    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            Log.d("NetworkMonitor", "Rețea disponibilă")
        }
        override fun onLost(network: Network) {
            Log.d("NetworkMonitor", "Rețea pierdută")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_network)
        val connectivityManager = getSystemService(ConnectivityManager::class.java)
        connectivityManager.registerDefaultNetworkCallback(networkCallback)
        lifecycleScope.launch {
            Log.d("NetworkMonitor", "Monitorizarea rețelei pornită")
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        val connectivityManager = getSystemService(ConnectivityManager::class.java)
        connectivityManager.unregisterNetworkCallback(networkCallback)
        Log.d("NetworkMonitor", "onDestroy: callback anulat")
    }
}

În onDestroy se anulează înregistrarea callback-ului de rețea. lifecycleScope se anulează automat la distrugerea ciclului de viață — anularea separată a corutinei nu este necesară. Callback-ul de rețea trebuie dezabonat obligatoriu, altfel va rămâne în sistem chiar și după distrugerea Activity.

Exemplul 2: onDestroy Fragment cu curățarea referințelor View

Fragment curăță corect referințele la View în onDestroyView, prevenind scurgerile de memorie cauzate de închideri.

kotlin
class ProfileFragment : Fragment() {
    private var avatarView: ImageView? = null
    private var progressBar: ProgressBar? = null
    private val imageLoader = ImageLoader()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        avatarView = view.findViewById(R.id.avatar)
        progressBar = view.findViewById(R.id.progress)
        loadProfile()
    }

    private fun loadProfile() {
        viewLifecycleOwner.lifecycleScope.launch {
            try {
                progressBar?.visibility = View.VISIBLE
                val bitmap = imageLoader.load("https://example.com/avatar.png")
                avatarView?.setImageBitmap(bitmap)
            } finally {
                progressBar?.visibility = View.GONE
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        avatarView = null
        progressBar = null
        imageLoader.cancel()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("ProfileFragment", "onDestroy: Fragment complet distrus")
    }
}

În onDestroyView referințele la View sunt setate la zero — aceasta previne scurgerea de memorie dacă închiderea din imageLoader reține o referință la avatarView. Fragmentul însuși și ViewModel-ul său rămân vii până la onDestroy. imageLoader.cancel() anulează încărcarea dacă Fragment părăsește ecranul.

Exemplul 3: Verificarea isFinishing în onDestroy

Utilizarea isFinishing() permite diferențierea dacă Activity se finalizează la comanda utilizatorului sau pentru recreare.

kotlin
class AnalyticsActivity : AppCompatActivity() {
    private val analytics = Analytics()

    override fun onDestroy() {
        if (isFinishing) {
            Log.d("AnalyticsActivity", "Activity se finalizează cu finish() — trimitem analitica")
            analytics.sendSessionEnd()
        } else {
            Log.d("AnalyticsActivity", "Activity se recrează (rotire/configurație) — nu trimitem analitica")
        }
        super.onDestroy()
    }
}

Verificarea isFinishing() — un model important pentru analitică, logare și curățarea datelor de sesiune. La rotire nu trebuie trimise evenimente de încheiere a sesiunii — utilizatorul încă lucrează cu aplicația. Conform Google Analytics, verificarea incorectă a isFinishing() este cauza a 40% dintre evenimentele de sesiune false.

Întrebări frecvente

Poate onDestroy să nu fie apelat?

Da, poate — la uciderea procesului de către sistem (process death), Force Stop de către utilizator sau finalizare accidentală. Conform datelor Google, aproximativ 5–8% dintre finalizările Activity au loc fără apelarea onDestroy. Dezvoltatorul nu trebuie să se bazeze pe onDestroy pentru salvarea datelor critice — folosiți onPause sau onSaveInstanceState.

Cu ce se deosebește onDestroy de finish()?

finish() — apelul care inițiază distrugerea Activity. onDestroy — callback-ul care este apelat în procesul de executare a finish(). finish() este obligatoriu pentru apelarea onDestroy la finalizarea normală. finish() poate fi apelat de sistem sau de dezvoltator, onDestroy — doar callback de sistem.

Trebuie apelat super.onDestroy() în Fragment?

Da, obligatoriu atât în Activity, cât și în Fragment. super.onDestroy() asigură curățarea corectă a ChildFragmentManager, LoaderManager și altor componente de sistem. Omiterea super.onDestroy() duce la scurgeri de memorie și erori la restaurarea fragmentelor.

Când este apelat onCleared() la ViewModel în raport cu onDestroy?

onCleared() este apelat după onDestroy Activity sau Fragment, când ViewModel nu mai este necesar. La rotirea ecranului onCleared() nu este apelat — ViewModel supraviețuiește onDestroy. Ordinea: onDestroy Activity/Fragment → (ViewModelStore se curăță) → onCleared().

Se poate lansa un Service din onDestroy?

Tehnic da, dar nu este recomandat. Activity este distrus imediat după onDestroy, iar Service-ul lansat rămâne fără control. Pentru sarcini de fundal utilizați WorkManager cu întârziere: WorkManager garantează executarea chiar și după finalizarea Activity și supraviețuiește process death.

Concluzii

  • onDestroy — callback-ul final al ciclului de viață al Activity și Fragment, apelat înainte de distrugerea completă a componentului.
  • Apelul onDestroy nu este garantat la process death — aproximativ 5–8% dintre finalizări au loc fără el.
  • În onDestroy trebuie eliberate: callback-uri de rețea, socket-uri, fluxuri de fișiere, BroadcastReceiver, ContentObserver.
  • ViewModel.onCleared() este apelat după onDestroy Activity — viewModelScope se anulează automat.
  • onDestroyView la Fragment (separat de onDestroy) — locul potrivit pentru zeroirea referințelor la View.
  • Verificarea isFinishing() în onDestroy permite distingerea finalizării finish() de recrearea la schimbări de configurație.
  • Nu vă bazați pe onDestroy pentru salvarea datelor — folosiți onPause sau onSaveInstanceState.

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