onStop — Android 中 Activity 的生命周期方法,当 Activity 对用户不再可见时由系统调用。Activity 在新的 Activity 完全覆盖它之后或应用程序最小化时进入 Stopped 状态。在 onStop 方法中,开发人员必须停止动画、释放摄像头和传感器资源、保存输入数据的草稿。根据 Android Vitals(Google,2025),正确处理 onStop 可将应用程序最小化时的 ANR(应用程序无响应)数量减少 35%。onStop 之后,系统可以调用 onRestart(返回屏幕)或 onDestroy(完全结束)。Android Developers 关于 Activity 生命周期的文档将 onStop 描述为可见状态和不可见状态之间的边界。
要点
onStop — 是 AppCompatActivity 类(及其前身 Activity)的回调方法,由 Android 操作系统在 Activity 对用户完全不可见时调用。此时,Activity 被另一个 Activity、对话框、系统启动器或锁定屏幕隐藏。从生命周期角度来看,onStop 在 onPause 之后调用,表示 Activity 不再在屏幕上可见,尽管 Activity 对象及其状态仍保留在内存中。
当 Activity 进入 Stopped(已停止)状态时,它会在 RAM 中保留其状态 — 所有字段、视图层次结构和 ViewModel 仍然可访问。这使 Stopped 与已销毁(Destroyed)状态区分开来,后者的 Activity 被完全移除。系统 UI 可以在内存不足时杀死处于 Stopped 状态的应用程序进程 — 这称为 process death(进程死亡)。开发人员必须在 onSaveInstanceState()(在 onStop 之前调用)中保存关键数据(草稿、滚动位置),以确保在进程被杀死时能够恢复。
根据 Android 兼容性定义文档(CDD)14+ 版本的规范,Stopped 状态的进程在 OOM Killer 杀死时具有较低的优先级 — 低于 Background 阶段的进程,但高于缓存的进程。根据 Google 的统计数据,68% 的进程终止发生在 Activity 处于 Stopped 状态时,而非 Paused 状态。
当 Activity 完全失去可见性时调用 onStop,无论原因如何:在当前 Activity 之上启动新的 Activity、最小化应用程序(按 Home 键)、锁定屏幕、来电或打开系统对话框。在所有情况下,Activity 首先收到 onPause(部分失去焦点),然后收到 onStop(完全失去可见性)。
调用 onStop 的主要场景:
重要的是要理解,onStop 不会在屏幕旋转时调用 — 在这种情况下,Activity 被销毁(onPause → onStop → onDestroy)并重新创建(onCreate → onStart → onResume)。例外情况 — 清单中的 android:configChanges="orientation" 标志,此时 Activity 不会重新创建,而是收到 onConfigurationChanged() 调用。
onStop 在 Activity 生命周期序列中占据核心位置 — 介于可见状态和不可见状态之间。完整序列:onCreate → onStart → onResume →(活动状态)→ onPause → onStop → onDestroy(或返回时的 onRestart → onStart → onResume)。
| 状态 | 方法 | 可见性 | 交互 | 内存 |
|---|---|---|---|---|
| Created | onCreate | 否 | 否 | 已分配 |
| Started | onStart | 部分 | 否 | 完全 |
| Resumed | onResume | 完全 | 是 | 完全 |
| Paused | onPause | 部分 | 否 | 完全 |
| Stopped | onStop | 否 | 否 | 完全* |
| Destroyed | onDestroy | 否 | 否 | 已释放 |
*在 Stopped 状态下,Activity 保留在内存中,但可能在资源不足时被系统杀死。Stopped 进程的终止优先级 — 倒数第二,仅高于空缓存进程。
onStop 和 onSaveInstanceState:系统在 onStop 之前调用 onSaveInstanceState(Bundle) 以保存动态 UI 状态。开发人员重写此方法以在 Bundle 中保存输入字段的值、RecyclerView 位置、选中的元素。即使 Activity 不会被销毁(用户只是最小化然后返回),Bundle 也会在配置更改时传递给 onCreate。Google 建议仅保存临时 UI 状态 — 而不是存储在 Activity 之外的存储库或 ViewModel 数据。
在 onStop 中,开发人员必须释放 Activity 不可见时不需要的所有资源。这可以降低电池、CPU 和内存的负载,并防止返回活动时出现 ANR。
在 onStop 中释放什么:
不要在 onStop 中做什么:不要执行长时间操作 — 在数据库中保存大量数据、网络请求、复杂计算。onStop 在主线程上执行,会阻塞返回 Activity。对于长时间操作,请使用带延迟的 WorkManager 或 viewModelScope 中的协程。不要释放 ViewModel 资源 — ViewModel 在 onStop 后仍然存在,返回时将被使用。
onPause 和 onStop 在可见性丧失的程度和必要操作的量上有所不同。onPause 在部分失去焦点时调用(例如打开对话框或系统菜单),onStop — 在完全失去可见性时。这种区别对于选择在每个阶段释放哪些资源非常重要。
| 特征 | onPause | onStop |
|---|---|---|
| 可见程度 | 部分可见 | 完全不可见 |
| 焦点 | 已失去 | 已失去 |
| 执行时间 | 最多 500 毫秒 | 最多 5 秒(ANR 超时) |
| 要释放的资源 | 关键的(媒体、摄像头) | 所有不可见的(传感器、动画、位置) |
| 恢复 | onResume | onRestart → onStart → onResume |
| 进程优先级 | 高(前台) | 中(后台) |
一般规则:在 onPause 中,释放 立即影响其他应用程序用户体验的系统资源(摄像头、媒体播放器),在 onStop 中 — 释放隐藏 Activity 时不需要的所有其他资源。Google 建议在 onPause 中保存关键用户数据(电子邮件草稿、设置),因为在快速切换时可能不会调用 onStop。
当用户返回到隐藏的 Activity 时,系统调用 onRestart → onStart → onResume。onRestart 方法表示 Activity 正在从 Stopped 状态返回。这是恢复 UI 和在 onStop 中释放的资源的重要阶段。
返回时的调用序列:
如果应用程序进程在 Stopped 状态下被系统杀死,则调用 onCreate 而不是 onRestart,并且从 onSaveInstanceState 获得的 Bundle 被传递用于恢复状态。这种情况(process death)— 是 Android 应用程序中最常见的错误原因之一:开发人员实现了 onRestart,但忘记考虑进程杀死后通过 onCreate 的恢复。
演示了在隐藏 Activity 时正确注销传感器和停止动画。返回屏幕后,资源在 onStart 中恢复。
class MainActivity : AppCompatActivity() {
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
private var rotationAnimator: ObjectAnimator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onStart() {
super.onStart()
accelerometer?.let {
sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
}
rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
rotationAnimator?.apply {
duration = 3000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
start()
}
}
override fun onStop() {
super.onStop()
sensorManager.unregisterListener(sensorListener)
rotationAnimator?.cancel()
}
override fun onRestart() {
super.onRestart()
Log.d("MainActivity", "Activity 从 Stopped 状态返回")
}
private val sensorListener = SensorEventListener { event, _ ->
Log.d("MainActivity", "Accel: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
}
}
代码在 onStart 中注册加速度计传感器并启动无限旋转动画。在 onStop 中,传感器被关闭,动画被取消 — 这可以防止隐藏 Activity 时的电池消耗。通过 onRestart → onStart 返回后,资源被重新创建。
使用 ViewModel + SavedStateHandle 的现代方法。表单数据在 onStop 时自动保存,无需手动 Bundle。
class FormViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
var email: String
get() = savedStateHandle["email"] ?: ""
set(value) { savedStateHandle["email"] = value }
var message: String
get() = savedStateHandle["message"] ?: ""
set(value) { savedStateHandle["message"] = value }
}
class FormActivity : AppCompatActivity() {
private val viewModel: FormViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_form)
Log.d("FormActivity", "onCreate: email=${viewModel.email}")
}
override fun onStop() {
super.onStop()
Log.d("FormActivity", "onStop: 数据已保存到 SavedStateHandle")
}
}
SavedStateHandle 在 onSaveInstanceState(在 onStop 之前调用)时自动将值保存到 Bundle。在屏幕旋转或进程终止时,数据可以无损失地恢复。Google 推荐使用 SavedStateHandle 来处理表单和草稿,而不是直接使用 onSaveInstanceState。
使用带有协程的 lifecycleScope 在进入 onStop 时异步保存数据。协程在 IO 调度器中启动,不会阻塞主线程。
class NoteActivity : AppCompatActivity() {
private val noteRepository = NoteRepository()
override fun onStop() {
lifecycleScope.launch(Dispatchers.IO) {
val text = findViewById<EditText>(R.id.note_content).text.toString()
noteRepository.saveDraft(text)
withContext(Dispatchers.Main) {
Log.d("NoteActivity", "草稿已保存在 onStop 中")
}
}
super.onStop()
}
}
lifecycleScope.launch 协程在 Activity 生命周期结束时自动取消。使用 Dispatchers.IO 可确保写入数据库或文件不会阻塞返回 Activity。根据 Google 的说法,lifecycleScope 中的协程是在 onStop 中执行异步操作的首选方式。
常见问题
onStop — Activity 变得不可见,但保留在 Stopped 状态的内存中。系统可以通过 onRestart 恢复 Activity。onDestroy — Activity 被销毁,内存被释放。onDestroy 之后,只能通过创建新的 Activity 实例(onCreate)来返回。
是的,必须调用。super.onStop() 确保系统组件(Fragment、LoaderManager、ViewModelStore)的正确运行。跳过 super.onStop() 可能导致内存泄漏和 Fragment 恢复不正确。始终最后或最先调用 super.onStop() — 顺序不重要,但调用是必需的。
在每个生命周期方法中使用 Log.d 或 Timber。按 Activity 的标签启用 logcat 过滤器。对于生产环境,使用 Android Vitals — Google 自动收集生命周期指标并在 Play 控制台中显示异常。还可以通过 ProcessLifecycleOwner 进行生命周期监控。
onStop 中未捕获的异常会导致应用程序 强制关闭。系统不会捕获生命周期回调中的异常。如果在 onStop 中执行可能抛出异常的操作(文件操作、网络),请将它们包装在 try-catch 中并记录错误,不要中断 super.onStop() 的执行。
不需要,如果没有引用,Activity 中的 Bitmap 将由 GC 回收。在 onStop 中强制释放(recycle())不是必需的,甚至是有害的 — 如果 Activity 通过 onRestart 返回,则需要重新加载 Bitmap。使用 Glide 或 Coil 加载图像 — 这些库自动管理缓存和生命周期。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。