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 — 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:
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).
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:
Când onDestroy NU este apelat:
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 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).
| Component | Metode de distrugere | Ordinea | ViewModel supraviețuiește |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | Nu (doar dacă ViewModelStore nu este salvat) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | Da, 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.
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:
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.
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:
La finish() (utilizatorul a apăsat „Înapoi”):
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.
Demonstrează gestionarea corectă a lifecycleScope în Activity: corutina este lansată pentru urmărirea stării rețelei și anulată în onDestroy.
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.
Fragment curăță corect referințele la View în onDestroyView, prevenind scurgerile de memorie cauzate de închideri.
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.
Utilizarea isFinishing() permite diferențierea dacă Activity se finalizează la comanda utilizatorului sau pentru recreare.
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
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.
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.
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.
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().
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
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.
Citiți și