onDestroy — фінальний метод життєвого циклу Activity та Fragment в Android, що викликається перед повним знищенням компонента. onDestroy сигналізує, що Activity або Fragment завершує свою роботу: всі ресурси повинні бути звільнені, вкладені фрагменти — знищені, ViewModel — очищений. За даними Google, onDestroy викликається в 100% випадків завершення Activity, але при вбивстві процесу (process death) система може пропустити виклик onDestroy повністю. Документація Android щодо onDestroy підкреслює, що цей метод не гарантує виклик при аварійному завершенні.
Головне
onDestroy — метод-колбек, який Android викликає перед тим, як остаточно знищити Activity або Fragment. Це остання можливість для розробника звільнити ресурси, скасувати фонові операції та завершити роботу з даними. Після виконання onDestroy екземпляр Activity/Fragment позначається для збирання сміття (GC) і більше не може бути використаний.
Причини виклику onDestroy:
Згідно зі статистикою Google Android Vitals (2025), близько 12% всіх випадків знищення Activity відбуваються через поворот екрана, 65% — через finish() і 23% — через зміну конфігурації. Відсоток вбивств процесів із пропуском onDestroy становить близько 5–8% залежно від пристроїв із малим об'ємом RAM (менше 4 ГБ).
onDestroy викликається в більшості стандартних сценаріїв, але є важливі винятки, які розробник зобов'язаний враховувати. Розуміння гарантій виклику onDestroy критично важливе для архітектури застосунку, особливо для збереження даних і скасування WorkManager-завдань.
Коли onDestroy викликається:
Коли onDestroy НЕ викликається:
Через відсутність гарантії виклику onDestroy Google рекомендує: ніколи не покладайтеся на onDestroy для збереження критичних даних. Використовуйте onSaveInstanceState(), WorkManager або Room з автоматичним збереженням. onDestroy — для звільнення ресурсів, але не для персистентності.
onDestroy існує як для Activity, так і для Fragment, але з різними контрактами. У Fragment життєвий цикл детальніший: окрім onDestroy є onDestroyView (знищення View-ієрархії) та onDetach (відв'язка від Activity).
| Компонент | Методи знищення | Порядок | ViewModel переживає |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | Ні (тільки якщо ViewModelStore не збережений) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | Так, якщо Fragment не видалений |
Ключова відмінність: у Fragment View перестворюється частіше, ніж сам Fragment. При повороті екрана Fragment проходить через onDestroyView (знищення View), але сам Fragment і його ViewModel залишаються живими. onDestroyView — правильне місце для очищення посилань на View, щоб уникнути витоків пам'яті. onDestroy Fragment — аналог onDestroy Activity, що викликається при повному видаленні Fragment.
Вкладені фрагменти (child fragments) знищуються до onDestroy батьківського Fragment. В Activity дочірні фрагменти отримують onDestroy при виклику onDestroy батьківської Activity. Порядок гарантований: фрагменти завершуються раніше, ніж Activity, що їх містить.
onDestroy призначений для звільнення всіх ресурсів, які не повинні жити довше Activity або Fragment. На відміну від onStop, який звільняє ресурси до повернення, onDestroy виконує фінальне очищення.
Чек-лист обов'язкових дій в onDestroy:
Чого НЕ робити в onDestroy: Не зберігайте дані в onDestroy — використовуйте onPause або onSaveInstanceState. Не запускайте нові Service або WorkManager-завдання — Activity буде знищена, і ви не зможете відстежити результат. Не намагайтеся оновити UI — View-ієрархія вже знищена або в процесі знищення; виклик findViewById() поверне null.
ViewModel спроектована так, щоб переживати onDestroy Activity при повороті екрана, але бути знищеною разом з Activity при finish(). Це асиметрична поведінка — головна причина плутанини у розробників.
При повороті екрана:
При finish() (користувач натиснув «Назад»):
Отже, скасовувати viewModelScope в onDestroy не потрібно — ViewModel зробить це самостійно. Якщо ви використовуєте lifecycleScope (прив'язаний до Activity, а не до ViewModel), скасуйте його в onDestroy через lifecycleScope.cancel() або керуйте Job вручну.
Демонструє коректне керування lifecycleScope в Activity: корутина запускається для відстеження мережевого статусу та скасовується в onDestroy.
class NetworkMonitorActivity : AppCompatActivity() {
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("NetworkMonitor", "Мережа доступна")
}
override fun onLost(network: Network) {
Log.d("NetworkMonitor", "Мережа втрачена")
}
}
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", "Спостереження за мережею запущено")
}
}
override fun onDestroy() {
super.onDestroy()
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.unregisterNetworkCallback(networkCallback)
Log.d("NetworkMonitor", "onDestroy: callback скасовано")
}
}
В onDestroy скасовується реєстрація мережевого колбека. lifecycleScope скасовується автоматично при знищенні життєвого циклу — окреме скасування корутини не потрібне. Мережевий callback обов'язково відписується, інакше він буде висіти в системі навіть після знищення Activity.
Fragment коректно очищає посилання на View в onDestroyView, запобігаючи витокам пам'яті через замикання.
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 повністю знищений")
}
}
В onDestroyView посилання на View обнуляються — це запобігає витоку пам'яті, якщо замикання в imageLoader затримує посилання на avatarView. Сам Fragment і його ViewModel залишаються живими до onDestroy. imageLoader.cancel() скасовує завантаження, якщо Fragment йде з екрана.
Використання isFinishing() дозволяє розрізнити, чи завершується Activity за командою користувача чи для перестворення.
class AnalyticsActivity : AppCompatActivity() {
private val analytics = Analytics()
override fun onDestroy() {
if (isFinishing) {
Log.d("AnalyticsActivity", "Activity завершується finish() — надсилаємо аналітику")
analytics.sendSessionEnd()
} else {
Log.d("AnalyticsActivity", "Activity перестворюється (поворот/конфігурація) — не надсилаємо аналітику")
}
super.onDestroy()
}
}
Перевірка isFinishing() — важливий патерн для аналітики, логування та очищення сесійних даних. При повороті не потрібно надсилати події завершення сеансу — користувач все ще працює із застосунком. За даними Google Analytics, неправильна перевірка isFinishing() — причина 40% хибних сесійних подій.
Часті запитання
Так, може — при вбивстві процесу системою (process death), Force Stop користувачем або аварійному завершенні. За даними Google, близько 5–8% завершень Activity відбуваються без виклику onDestroy. Розробник не повинен покладатися на onDestroy для збереження критичних даних — використовуйте onPause або onSaveInstanceState.
finish() — виклик, що ініціює знищення Activity. onDestroy — колбек, який викликається в процесі виконання finish(). finish() обов'язковий для виклику onDestroy при штатному завершенні. finish() може бути викликаний системою або розробником, onDestroy — тільки системний колбек.
Так, обов'язково як в Activity, так і в Fragment. super.onDestroy() забезпечує коректне очищення ChildFragmentManager, LoaderManager та інших системних компонентів. Пропуск super.onDestroy() призводить до витоків пам'яті та багів із відновленням фрагментів.
onCleared() викликається після onDestroy Activity або Fragment, коли ViewModel більше не потрібна. При повороті екрана onCleared() не викликається — ViewModel переживає onDestroy. Порядок: onDestroy Activity/Fragment → (ViewModelStore очищається) → onCleared().
Технічно так, але не рекомендується. Activity негайно знищується після onDestroy, і запущений Service залишається без контролю. Для фонових завдань використовуйте WorkManager із затримкою: WorkManager гарантує виконання навіть після завершення Activity та переживає process death.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також