onDestroy — آخرین متد چرخه حیات Activity و Fragment در اندروید که قبل از نابودی کامل کامپوننت فراخوانی میشود. onDestroy نشان میدهد که Activity یا Fragment کار خود را پایان میدهد: همه منابع باید آزاد شوند، fragmentهای تو در تو نابود شوند، ViewModel پاک شود. طبق دادههای Google، onDestroy در 100% موارد پایان Activity فراخوانی میشود، اما هنگام کشته شدن پردازه (process death) سیستم ممکن است فراخوانی onDestroy را کاملاً نادیده بگیرد. مستندات اندروید درباره onDestroy تأکید میکند که این متد در پایان اضطراری تضمین نمیشود.
نکات اصلی
onDestroy — متد بازفراخوانی است که اندروید قبل از نابودی نهایی 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 فراخوانی میشود.
fragmentهای تو در تو (child fragments) قبل از onDestroy Fragment والد نابود میشوند. در Activity، fragmentهای فرزند هنگام فراخوانی onDestroy Activity والد onDestroy دریافت میکنند. ترتیب تضمین شده است: fragmentها زودتر از Activity حاوی آنها پایان مییابند.
onDestroy برای آزادسازی تمام منابعی طراحی شده است که نباید بیشتر از Activity یا Fragment عمر کنند. برخلاف onStop که منابع را تا زمان بازگشت آزاد میکند، onDestroy پاکسازی نهایی را انجام میدهد.
چکلیست اقدامات اجباری در onDestroy:
در onDestroy چه کاری انجام ندهیم: دادهها را در onDestroy ذخیره نکنید — از onPause یا onSaveInstanceState استفاده کنید. Service یا وظایف WorkManager جدید راهاندازی نکنید — Activity نابود میشود و نمیتوانید نتیجه را پیگیری کنید. سعی نکنید UI را بهروزرسانی کنید — سلسلهمراتب View قبلاً نابود شده یا در حال نابودی است; فراخوانی findViewById() null برمیگرداند.
ViewModel طوری طراحی شده است که هنگام چرخش صفحه از onDestroy Activity جان سالم به در ببرد، اما در finish() همراه با Activity نابود شود. این رفتار نامتقارن — دلیل اصلی سردرگمی برنامهنویسان است.
هنگام چرخش صفحه:
هنگام 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: بازفراخوانی لغو شد")
}
}
در onDestroy ثبت بازفراخوانی شبکه لغو میشود. lifecycleScope با نابودی چرخه حیات به طور خودکار لغو میشود — لغو جداگانه کوروتین لازم نیست. بازفراخوانی شبکه حتماً باید لغو اشتراک شود، در غیر این صورت حتی پس از نابودی 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() منجر به نشت حافظه و اشکالات در بازیابی fragmentها میشود.
onCleared() پس از onDestroy Activity یا Fragment فراخوانی میشود، زمانی که ViewModel دیگر نیاز نیست. هنگام چرخش صفحه onCleared() فراخوانی نمیشود — ViewModel از onDestroy جان سالم به در میبرد. ترتیب: onDestroy Activity/Fragment → (ViewModelStore پاک میشود) → onCleared().
از نظر فنی بله، اما توصیه نمیشود. Activity بلافاصله پس از onDestroy نابود میشود و Service راهاندازی شده بدون کنترل میماند. برای وظایف پسزمینه از WorkManager با تأخیر استفاده کنید: WorkManager اجرا را حتی پس از پایان Activity تضمین میکند و از process death جان سالم به در میبرد.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید