onDestroy: co to je, ukončení Activity v Androidu

Autor: IT Sectr Publikováno: 2026-03-04 Doba čtení: 8 min

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 — poslední volání před zničením Activity nebo Fragment, určené pro finální čištění zdrojů.
  • Volání onDestroy není garantováno při zabití procesu systémem (process death) — nespoléhejte na něj pro ukládání kritických dat.
  • V onDestroy je třeba zrušit úlohy na pozadí, zavolat sockety a databáze, vyčistit ViewModelStore.
  • Rozdíl od onStop: onStop — ztráta viditelnosti (Activity žije v paměti), onDestroy — úplné zničení.
  • isFinishing() v onDestroy ukazuje, zda Activity končí na příkaz uživatele (finish()) nebo rozhodnutím systému.

onDestroy: co to je v Androidu?

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:

  • Explicitní volání finish() — uživatel stiskl „Zpět" nebo vývojář zavolal finishActivity().
  • Otočení obrazovky — Activity je zničeno a znovu vytvořeno s novou konfigurací.
  • Změna konfigurace — klávesnice, změna jazyka, změna velikosti obrazovky (multi-window).
  • Rozhodnutí systému — Android zabíjí Activity pro uvolnění zdrojů (ale onDestroy nemusí být voláno).

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).

Kdy je onDestroy voláno — a kdy ne

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:

  • Uživatel stiskne tlačítko „Zpět" — Activity.finish() → onPause → onStop → onDestroy.
  • Otočení obrazovky — Activity je zničeno (onPause → onStop → onDestroy), poté znovu vytvořeno.
  • Změna konfigurace — systémové nastavení vyžadující nové vytvoření Activity.
  • Volání finishAffinity() — ukončení všech Activity v zásobníku.
  • Odstranění Fragment z FragmentManager — Fragment obdrží onPause → onStop → onDestroyView → onDestroy → onDetach.

Kdy onDestroy NENÍ voláno:

  • Zabití procesu systémem (process death) — Android zabíjí celý proces aplikace při nedostatku paměti. Activity neobdrží onDestroy, protože proces je ukončen na úrovni jádra Linux.
  • Nouzové ukončení — nezachycená výjimka v hlavním vlákně zabíjí aplikaci bez volání onDestroy.
  • Force Stop — uživatel vynuceně zastaví aplikaci v nastavení.

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 v Activity a Fragment: společné a rozdíly

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).

KomponentaMetody zničeníPořadíViewModel přežije
ActivityonDestroyonPause → onStop → onDestroyNe (pouze pokud ViewModelStore není uložen)
FragmentonDestroyView, onDestroy, onDetachonPause → onStop → onDestroyView → onDestroy → onDetachAno, 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.

Co dělat v onDestroy: kontrolní seznam čištění

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:

  • Zrušení coroutine a Flow — zrušte joby, které nejsou vázány na viewModelScope. viewModelScope se ruší automaticky, ale lifecycleScope je vázán na životní cyklus Activity.
  • Zavření socketů a kanálů — WebSocket (OkHttp), BluetoothSocket, ServerSocket. Držet je otevřené po zničení je únik systémových zdrojů.
  • Zavření souborů a proudů — FileInputStream, FileOutputStream, Cursor. Cursor může způsobit ANR na ContentProvider, pokud není uzavřen.
  • Odhlášení z ContentObserver — pokud Activity sleduje změny obsahu (kontakty, mediální knihovna).
  • Odhlášení z BroadcastReceiver — dynamicky registrované receivery musí být zrušeny.
  • Zavření databáze — Room zavírá spojení automaticky při zničení Application, ale přímé SQLiteDatabase vyžaduje ruční close().

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.

onDestroy a ViewModel: spolupráce

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:

  • Activity: onPause → onStop → onDestroy (Activity zničeno).
  • ViewModel: NEZNIČEN — ViewModelStore je zachován a předán novému Activity.
  • Nové Activity: onCreate → onStart → onResume, obdrží stejný ViewModel.

Při finish() (uživatel stiskl „Zpět"):

  • Activity: onPause → onStop → onDestroy.
  • ViewModel: onCleared() — voláno po onDestroy Activity.
  • Všechny coroutine viewModelScope jsou automaticky zrušeny.

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ě.

Příklady kódu s onDestroy v Kotlin

Příklad 1: onDestroy Activity se zrušením coroutine lifecycleScope

Ukazuje správnou správu lifecycleScope v Activity: coroutine je spuštěna pro sledování stavu sítě a zrušena v onDestroy.

kotlin
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.

Příklad 2: onDestroy Fragment s čištěním referencí View

Fragment správně čistí reference na View v onDestroyView, čímž předchází únikům paměti způsobeným uzávěry.

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 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.

Příklad 3: Kontrola isFinishing v onDestroy

Použití isFinishing() umožňuje rozlišit, zda Activity končí na příkaz uživatele nebo kvůli novému vytvoření.

kotlin
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

Může onDestroy nebýt voláno?

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.

Čím se onDestroy liší od finish()?

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.

Je třeba volat super.onDestroy() ve Fragment?

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ů.

Kdy je voláno onCleared() u ViewModel ve vztahu k onDestroy?

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().

Lze spustit Service z onDestroy?

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í

  • onDestroy — finální callback životního cyklu Activity a Fragment, volaný před úplným zničením komponenty.
  • Volání onDestroy není garantováno při process death — přibližně 5–8% ukončení probíhá bez něj.
  • V onDestroy je třeba uvolnit: síťové callbacky, sockety, souborové proudy, BroadcastReceiver, ContentObserver.
  • ViewModel.onCleared() je voláno po onDestroy Activity — viewModelScope je automaticky zrušen.
  • onDestroyView ve Fragment (odděleně od onDestroy) — správné místo pro vynulování referencí na View.
  • Kontrola isFinishing() v onDestroy umožňuje rozlišit ukončení finish() od nového vytvoření při změnách konfigurace.
  • Nespoléhejte na onDestroy pro ukládání dat — použijte onPause nebo onSaveInstanceState.

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í.

Prodiskutovat projekt

Přečtěte si také