onDestroy — finální metoda životního cyklu Activity a Fragment v Androidu, volaná před úplným zničením komponenty. onDestroy signalizuje, že Activity nebo Fragment končí svou práci: všechny zdroje musí být uvolněny, vnořené fragmenty — zničeny, ViewModel — vyčištěn. Podle údajů Google je onDestroy voláno ve 100% případů ukončení Activity, ale při zabití procesu (process death) může systém volání onDestroy zcela přeskočit. Dokumentace Androidu k onDestroy zdůrazňuje, že tato metoda negarantuje volání při nouzovém ukončení.
Hlavní body
onDestroy — metoda zpětného volání, kterou Android volá před definitivním zničením Activity nebo Fragment. To je poslední šance pro vývojáře uvolnit zdroje, zrušit operace na pozadí a dokončit práci s daty. Po provedení onDestroy je instance Activity/Fragment označena pro garbage collector (GC) a již nemůže být použita.
Důvody volání onDestroy:
Podle statistik Google Android Vitals (2025) je přibližně 12% všech případů zničení Activity způsobeno otočením obrazovky, 65% finish() a 23% změnou konfigurace. Procento zabití procesů s přeskočením onDestroy je přibližně 5–8% v závislosti na zařízeních s malou RAM (méně než 4 GB).
onDestroy je voláno ve většině standardních scénářů, ale existují důležité výjimky, které musí vývojář zohlednit. Porozumění zárukám volání onDestroy je kritické pro architekturu aplikace, zejména pro ukládání dat a rušení úloh WorkManager.
Kdy je onDestroy voláno:
Kdy onDestroy NENÍ voláno:
Kvůli chybějící záruce volání onDestroy Google doporučuje: nikdy nespoléhejte na onDestroy pro ukládání kritických dat. Použijte onSaveInstanceState(), WorkManager nebo Room s automatickým ukládáním. onDestroy — pro uvolňování zdrojů, ne pro perzistenci.
onDestroy existuje jak pro Activity, tak pro Fragment, ale s různými kontrakty. U Fragment je životní cyklus podrobnější: kromě onDestroy existuje onDestroyView (zničení hierarchie View) a onDetach (odpojení od Activity).
| Komponenta | Metody zničení | Pořadí | ViewModel přežije |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | Ne (pouze pokud ViewModelStore není uložen) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | Ano, pokud Fragment není odstraněn |
Klíčový rozdíl: u Fragment je View vytvářeno častěji než samotný Fragment. Při otočení obrazovky Fragment prochází onDestroyView (zničení View), ale samotný Fragment a jeho ViewModel zůstávají živé. onDestroyView — správné místo pro čištění referencí na View, aby se předešlo únikům paměti. onDestroy Fragment — analogie onDestroy Activity, volané při úplném odstranění Fragment.
Vnořené fragmenty (child fragments) jsou zničeny před onDestroy rodičovského Fragment. V Activity obdrží podřízené fragmenty onDestroy při volání onDestroy rodičovského Activity. Pořadí je garantováno: fragmenty končí dříve než Activity, které je obsahuje.
onDestroy je určeno pro uvolnění všech zdrojů, které by neměly žít déle než Activity nebo Fragment. Na rozdíl od onStop, který uvolňuje zdroje do návratu, onDestroy provádí finální čištění.
Kontrolní seznam povinných akcí v onDestroy:
Co NEDĚLAT v onDestroy: Neukládejte data v onDestroy — použijte onPause nebo onSaveInstanceState. Nespouštějte nové Service nebo WorkManager — Activity bude zničeno a nebudete moci sledovat výsledek. Nepokoušejte se aktualizovat UI — hierarchie View je již zničena nebo v procesu ničení; volání findViewById() vrátí null.
ViewModel je navržen tak, aby přežil onDestroy Activity při otočení obrazovky, ale byl zničen spolu s Activity při finish(). Toto asymetrické chování — hlavní příčina zmatku mezi vývojáři.
Při otočení obrazovky:
Při finish() (uživatel stiskl „Zpět"):
Rušení viewModelScope v onDestroy tedy není nutné — ViewModel to udělá sám. Pokud používáte lifecycleScope (vázaný na Activity, ne na ViewModel), zrušte jej v onDestroy pomocí lifecycleScope.cancel() nebo spravujte Job ručně.
Ukazuje správnou správu lifecycleScope v Activity: coroutine je spuštěna pro sledování stavu sítě a zrušena v onDestroy.
class NetworkMonitorActivity : AppCompatActivity() {
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("NetworkMonitor", "Síť dostupná")
}
override fun onLost(network: Network) {
Log.d("NetworkMonitor", "Síť ztracena")
}
}
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", "Sledování sítě spuštěno")
}
}
override fun onDestroy() {
super.onDestroy()
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.unregisterNetworkCallback(networkCallback)
Log.d("NetworkMonitor", "onDestroy: callback zrušen")
}
}
V onDestroy je zrušena registrace síťového callbacku. lifecycleScope je automaticky zrušen při zničení životního cyklu — samostatné rušení coroutine není vyžadováno. Síťový callback musí být odhlášen, jinak zůstane viset v systému i po zničení Activity.
Fragment správně čistí reference na View v onDestroyView, čímž předchází únikům paměti způsobeným uzávěry.
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 zcela zničen")
}
}
V onDestroyView jsou reference na View vynulovány — to zabraňuje úniku paměti, pokud uzávěr v imageLoader drží referenci na avatarView. Samotný Fragment a jeho ViewModel zůstávají živé až do onDestroy. imageLoader.cancel() ruší načítání, pokud Fragment opouští obrazovku.
Použití isFinishing() umožňuje rozlišit, zda Activity končí na příkaz uživatele nebo kvůli novému vytvoření.
class AnalyticsActivity : AppCompatActivity() {
private val analytics = Analytics()
override fun onDestroy() {
if (isFinishing) {
Log.d("AnalyticsActivity", "Activity končí finish() — posíláme analytiku")
analytics.sendSessionEnd()
} else {
Log.d("AnalyticsActivity", "Activity je znovu vytvářeno (otáčení/konfigurace) — neposíláme analytiku")
}
super.onDestroy()
}
}
Kontrola isFinishing() — důležitý vzor pro analytiku, logování a čištění dat relace. Při otočení není třeba odesílat události konce relace — uživatel stále pracuje s aplikací. Podle Google Analytics je nesprávná kontrola isFinishing() příčinou 40% falešných událostí relace.
Často kladené otázky
Ano, může — při zabití procesu systémem (process death), Force Stop uživatelem nebo nouzovém ukončení. Podle údajů Google přibližně 5–8% ukončení Activity probíhá bez volání onDestroy. Vývojář by neměl spoléhat na onDestroy pro ukládání kritických dat — použijte onPause nebo onSaveInstanceState.
finish() — volání, které iniciuje zničení Activity. onDestroy — callback, který je volán v průběhu provádění finish(). finish() je povinné pro volání onDestroy při standardním ukončení. finish() může být voláno systémem nebo vývojářem, onDestroy — pouze systémový callback.
Ano, nezbytně jak v Activity, tak ve Fragment. super.onDestroy() zajišťuje správné čištění ChildFragmentManager, LoaderManager a dalších systémových komponent. Vynechání super.onDestroy() vede k únikům paměti a chybám při obnově fragmentů.
onCleared() je voláno po onDestroy Activity nebo Fragment, když ViewModel již není potřeba. Při otočení obrazovky onCleared() není voláno — ViewModel přežije onDestroy. Pořadí: onDestroy Activity/Fragment → (ViewModelStore je vyčištěn) → onCleared().
Technicky ano, ale nedoporučuje se. Activity je okamžitě zničeno po onDestroy a spuštěný Service zůstává bez kontroly. Pro úlohy na pozadí použijte WorkManager se zpožděním: WorkManager garantuje provedení i po ukončení Activity a přežije process death.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také