onDestroy — Android中Activity和Fragment生命周期的最终方法,在组件完全销毁之前调用。onDestroy表示Activity或Fragment即将结束其工作:所有资源必须释放,嵌套的fragment必须销毁,ViewModel必须清理。根据Google数据,onDestroy在Activity结束的100%情况下会被调用,但在进程终止(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%,具体取决于内存较小的设备(低于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引用的正确位置,以避免内存泄漏。Fragment的onDestroy — 类似于Activity的onDestroy,在Fragment完全移除时调用。
嵌套的fragment(子fragment)在父Fragment的onDestroy之前被销毁。在Activity中,当调用父Activity的onDestroy时,子fragment会收到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()时(用户按下了"返回"键):
因此,在onDestroy中取消viewModelScope是不必要的 — ViewModel会自行处理。如果您使用lifecycleScope(绑定到Activity,而非ViewModel),请在onDestroy中通过lifecycleScope.cancel()取消它,或手动管理Job。
演示Activity中lifecycleScope的正确管理:协程启动用于跟踪网络状态并在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在onDestroyView中正确清理View引用,防止闭包引起的内存泄漏。
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。如果Fragment离开屏幕,imageLoader.cancel()会取消加载。
使用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)、用户强制停止或意外终止时。根据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恢复的bug。
onCleared()在Activity或Fragment的onDestroy之后调用,当ViewModel不再需要时。屏幕旋转时onCleared()不被调用 — ViewModel在onDestroy后存活。顺序:onDestroy Activity/Fragment →(ViewModelStore被清理)→ onCleared()。
技术上可以,但不推荐。Activity在onDestroy后立即被销毁,已启动的Service将不受控制。对于后台任务,请使用带延迟的WorkManager:WorkManager即使在Activity结束后也能保证执行,并且能存活process death。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。