onDestroy:什么是它,Android中Activity的结束

作者: IT Sectr 发布日期: 2026-03-04 阅读时间: 8 分钟

onDestroy — Android中Activity和Fragment生命周期的最终方法,在组件完全销毁之前调用。onDestroy表示Activity或Fragment即将结束其工作:所有资源必须释放,嵌套的fragment必须销毁,ViewModel必须清理。根据Google数据,onDestroy在Activity结束的100%情况下会被调用,但在进程终止(process death)时,系统可能完全跳过onDestroy的调用。Android关于onDestroy的文档强调,该方法在意外终止时不能保证被调用。

要点

  • onDestroy — Activity或Fragment销毁前的最后一次调用,用于最终资源清理。
  • 系统杀死进程(process death)时不保证调用onDestroy — 不要依赖它来保存关键数据。
  • 在onDestroy中必须取消后台任务、关闭套接字和数据库、清理ViewModelStore。
  • 与onStop的区别:onStop — 失去可见性(Activity仍在内存中),onDestroy — 完全销毁。
  • onDestroy中的isFinishing()显示Activity是应用户命令(finish())还是系统决定结束。

onDestroy:在Android中是什么?

onDestroy — Android在最终销毁Activity或Fragment之前调用的回调方法。这是开发者释放资源、取消后台操作和结束数据处理的最后机会。执行onDestroy后,Activity/Fragment实例被标记为垃圾回收(GC)并且不能再使用。

调用onDestroy的原因:

  • 显式调用finish() — 用户按下"返回"键或开发者调用了finishActivity()。
  • 屏幕旋转 — Activity被销毁并以新配置重新创建。
  • 配置变更 — 键盘、语言切换、屏幕尺寸变化(多窗口)。
  • 系统决定 — Android为释放资源而杀死Activity(但onDestroy可能不会被调用)。

根据Google Android Vitals(2025)统计数据,约12%的Activity销毁案例由屏幕旋转引起,65%由finish()引起,23%由配置变更引起。跳过onDestroy的进程杀死比例约为5–8%,具体取决于内存较小的设备(低于4 GB)。

何时调用onDestroy — 何时不调用

onDestroy在大多数标准场景下会被调用,但存在开发人员必须考虑的重要例外。理解onDestroy的调用保证对于应用程序架构至关重要,特别是对于数据保存和取消WorkManager任务。

何时调用onDestroy:

  • 用户按下"返回"按钮 — Activity.finish() → onPause → onStop → onDestroy。
  • 屏幕旋转 — Activity被销毁(onPause → onStop → onDestroy),然后重新创建。
  • 配置变更 — 需要重新创建Activity的系统设置。
  • 调用finishAffinity() — 结束堆栈中的所有Activity。
  • 从FragmentManager中移除Fragment — Fragment收到onPause → onStop → onDestroyView → onDestroy → onDetach。

何时不调用onDestroy:

  • 系统杀死进程(process death) — Android在内存不足时杀死整个应用程序进程。Activity收不到onDestroy,因为进程在Linux内核级别终止。
  • 意外终止 — 主线程中未捕获的异常杀死应用程序而不调用onDestroy。
  • 强制停止 — 用户在设置中强制停止应用程序。

由于缺乏onDestroy调用的保证,Google建议:永远不要依赖onDestroy来保存关键数据。使用onSaveInstanceState()、WorkManager或带自动保存的Room。onDestroy — 用于释放资源,而不是持久化数据。

Activity和Fragment中的onDestroy:共性与差异

onDestroy同时存在于Activity和Fragment,但具有不同的约定。Fragment的生命周期更详细:除了onDestroy还有onDestroyView(销毁View层次结构)和onDetach(从Activity分离)。

组件销毁方法顺序ViewModel存活
ActivityonDestroyonPause → onStop → onDestroy否(除非ViewModelStore已保存)
FragmentonDestroyView, onDestroy, onDetachonPause → 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中做什么:清理检查清单

onDestroy旨在释放所有不应比Activity或Fragment存活更久的资源。与onStop在返回前释放资源不同,onDestroy执行最终清理。

onDestroy中必须执行的操作清单:

  • 取消协程和Flow — 取消未绑定到viewModelScope的job。viewModelScope会自动取消,但lifecycleScope绑定到Activity的生命周期。
  • 关闭套接字和通道 — WebSocket(OkHttp)、BluetoothSocket、ServerSocket。销毁后保持它们打开会导致系统资源泄漏。
  • 关闭文件和流 — FileInputStream、FileOutputStream、Cursor。如果未关闭,Cursor可能会在ContentProvider上引起ANR。
  • 取消ContentObserver订阅 — 如果Activity监视内容变化(联系人、媒体库)。
  • 取消BroadcastReceiver订阅 — 动态注册的接收器必须被取消。
  • 关闭数据库 — Room在Application销毁时自动关闭连接,但直接使用SQLiteDatabase需要手动close()。

在onDestroy中不要做什么:不要在onDestroy中保存数据 — 使用onPause或onSaveInstanceState。不要启动新的Service或WorkManager任务 — Activity将被销毁且无法跟踪结果。不要尝试更新UI — View层次结构已销毁或正在销毁;调用findViewById()返回null。

onDestroy和ViewModel:协同工作

ViewModel被设计为在屏幕旋转时存活onDestroy Activity,但在finish()时随Activity一起销毁。这种不对称行为是开发人员困惑的主要原因。

屏幕旋转时:

  • Activity:onPause → onStop → onDestroy(Activity已销毁)。
  • ViewModel:未销毁 — ViewModelStore被保留并传递给新的Activity。
  • 新Activity:onCreate → onStart → onResume,接收相同的ViewModel。

finish()时(用户按下了"返回"键):

  • Activity:onPause → onStop → onDestroy。
  • ViewModel:onCleared() — 在Activity的onDestroy之后调用。
  • 所有viewModelScope协程自动取消。

因此,在onDestroy中取消viewModelScope是不必要的 — ViewModel会自行处理。如果您使用lifecycleScope(绑定到Activity,而非ViewModel),请在onDestroy中通过lifecycleScope.cancel()取消它,或手动管理Job。

Kotlin中onDestroy的代码示例

示例1:取消lifecycleScope协程的onDestroy Activity

演示Activity中lifecycleScope的正确管理:协程启动用于跟踪网络状态并在onDestroy中取消。

kotlin
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销毁后它也会挂在系统中。

示例2:清理View引用的onDestroy Fragment

Fragment在onDestroyView中正确清理View引用,防止闭包引起的内存泄漏。

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已完全销毁")
    }
}

在onDestroyView中,View引用被置空 — 如果imageLoader中的闭包持有对avatarView的引用,这可以防止内存泄漏。Fragment本身及其ViewModel保持存活直到onDestroy。如果Fragment离开屏幕,imageLoader.cancel()会取消加载。

示例3:在onDestroy中检查isFinishing

使用isFinishing()可以区分Activity是应用户命令结束还是为重建而结束。

kotlin
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%虚假会话事件的原因。

常见问题

onDestroy可能不被调用吗?

是的,可能 — 在系统杀死进程(process death)、用户强制停止或意外终止时。根据Google数据,约5–8%的Activity终止发生在没有调用onDestroy的情况下。开发人员不应依赖onDestroy来保存关键数据 — 请使用onPause或onSaveInstanceState。

onDestroy与finish()有什么区别?

finish() — 启动Activity销毁的调用。onDestroy — 在finish()执行过程中调用的回调。正常终止时,finish()是调用onDestroy所必需的。finish()可以由系统或开发人员调用,onDestroy — 仅系统回调。

在Fragment中需要调用super.onDestroy()吗?

是的,必须在Activity和Fragment中都需要。super.onDestroy()确保ChildFragmentManager、LoaderManager和其他系统组件的正确清理。跳过super.onDestroy()会导致内存泄漏和fragment恢复的bug。

ViewModel的onCleared()相对于onDestroy何时调用?

onCleared()在Activity或Fragment的onDestroy之后调用,当ViewModel不再需要时。屏幕旋转时onCleared()不被调用 — ViewModel在onDestroy后存活。顺序:onDestroy Activity/Fragment →(ViewModelStore被清理)→ onCleared()。

可以从onDestroy启动Service吗?

技术上可以,但不推荐。Activity在onDestroy后立即被销毁,已启动的Service将不受控制。对于后台任务,请使用带延迟的WorkManager:WorkManager即使在Activity结束后也能保证执行,并且能存活process death。

总结

  • onDestroy — Activity和Fragment生命周期的最终回调,在组件完全销毁之前调用。
  • process death时onDestroy的调用不保证 — 约5–8%的终止发生在没有它的情况下。
  • 在onDestroy中必须释放:网络回调、套接字、文件流、BroadcastReceiver、ContentObserver。
  • ViewModel.onCleared()在Activity的onDestroy之后调用 — viewModelScope自动取消。
  • Fragment中的onDestroyView(独立于onDestroy) — 置空View引用的正确位置。
  • onDestroy中的isFinishing()检查可以区分finish()终止与配置变更时的重建。
  • 不要依赖onDestroy来保存数据 — 使用onPause或onSaveInstanceState。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读