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 GB).
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() e задължително за извикване на 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също