onStop — 是什么,Android 生命周期中隐藏 Activity

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

onStop — Android 中 Activity 的生命周期方法,当 Activity 对用户不再可见时由系统调用。Activity 在新的 Activity 完全覆盖它之后或应用程序最小化时进入 Stopped 状态。在 onStop 方法中,开发人员必须停止动画、释放摄像头和传感器资源、保存输入数据的草稿。根据 Android Vitals(Google,2025),正确处理 onStop 可将应用程序最小化时的 ANR(应用程序无响应)数量减少 35%。onStop 之后,系统可以调用 onRestart(返回屏幕)或 onDestroy(完全结束)。Android Developers 关于 Activity 生命周期的文档将 onStop 描述为可见状态和不可见状态之间的边界。

要点

  • onStop — 在 Activity 完全失去可见性时调用的方法,但 Activity 仍在内存中。
  • onStop 之后,Activity 进入 Stopped 状态 — 在内存中存活,但不可见且不响应用户交互。
  • 系统可以在返回 Activity 时调用 onRestart → onStart → onResume,或在结束时调用 onDestroy。
  • 在 onStop 中需要释放资源:停止动画、关闭传感器和摄像头、保存临时数据。
  • 正确实现 onStop — 是多任务和最小化时应用程序稳定性的关键因素。

Android 中的 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 状态。

何时调用 onStop:场景和顺序

当 Activity 完全失去可见性时调用 onStop,无论原因如何:在当前 Activity 之上启动新的 Activity、最小化应用程序(按 Home 键)、锁定屏幕、来电或打开系统对话框。在所有情况下,Activity 首先收到 onPause(部分失去焦点),然后收到 onStop(完全失去可见性)。

调用 onStop 的主要场景:

  • 在当前 Activity 之上启动新的 Activity — 当前 Activity 收到 onPause,然后是 onStop;新 Activity 经历 onCreate → onStart → onResume。
  • 最小化应用程序(Home) — Activity 在 200-300 毫秒内进入 onPause → onStop,在 Stopped 状态下保留在内存中。
  • 锁定屏幕 — 系统调用 onPause → onStop,因为锁定屏幕完全覆盖了 Activity。
  • 来电 — 电话 Activity(拨号器)启动在顶部,当前 Activity 进入 onStop。
  • 切换到其他应用程序(最近应用) — Activity 被隐藏,收到 onStop,但保留在进程缓存中。

重要的是要理解,onStop 不会在屏幕旋转时调用 — 在这种情况下,Activity 被销毁(onPause → onStop → onDestroy)并重新创建(onCreate → onStart → onResume)。例外情况 — 清单中的 android:configChanges="orientation" 标志,此时 Activity 不会重新创建,而是收到 onConfigurationChanged() 调用。

Activity 生命周期中的 onStop

onStop 在 Activity 生命周期序列中占据核心位置 — 介于可见状态和不可见状态之间。完整序列:onCreate → onStart → onResume →(活动状态)→ onPause → onStop → onDestroy(或返回时的 onRestart → onStart → onResume)。

状态方法可见性交互内存
CreatedonCreate已分配
StartedonStart部分完全
ResumedonResume完全完全
PausedonPause部分完全
StoppedonStop完全*
DestroyedonDestroy已释放

*在 Stopped 状态下,Activity 保留在内存中,但可能在资源不足时被系统杀死。Stopped 进程的终止优先级 — 倒数第二,仅高于空缓存进程。

onStop 和 onSaveInstanceState:系统在 onStop 之前调用 onSaveInstanceState(Bundle) 以保存动态 UI 状态。开发人员重写此方法以在 Bundle 中保存输入字段的值、RecyclerView 位置、选中的元素。即使 Activity 不会被销毁(用户只是最小化然后返回),Bundle 也会在配置更改时传递给 onCreate。Google 建议仅保存临时 UI 状态 — 而不是存储在 Activity 之外的存储库或 ViewModel 数据。

在 onStop 中释放哪些资源

在 onStop 中,开发人员必须释放 Activity 不可见时不需要的所有资源。这可以降低电池、CPU 和内存的负载,并防止返回活动时出现 ANR。

在 onStop 中释放什么:

  • 动画和过渡 — 停止 ObjectAnimator、ValueAnimator、ViewPropertyAnimator。不可见 Activity 中正在运行的动画是浪费 GPU 周期。
  • 传感器(Sensors) — 从 SensorManager 注销(加速度计、陀螺仪、磁力计)。即使 Activity 被隐藏,传感器也会消耗电量。
  • 摄像头和麦克风 — 释放 Camera2 或 CameraX,停止 MediaRecorder。在隐藏的 Activity 中保持摄像头活动是 Google Play 政策禁止的。
  • 位置监听器(LocationListener) — 从 FusedLocationProviderClient 或 LocationManager 注销。地理位置是最耗电的资源。
  • 网络监听器 — 关闭 WebSocket,取消后台不需要的 HTTP 请求。
  • MediaPlayer 和 ExoPlayer — 如果播放不应在后台继续,则暂停或停止。

不要在 onStop 中做什么:不要执行长时间操作 — 在数据库中保存大量数据、网络请求、复杂计算。onStop 在主线程上执行,会阻塞返回 Activity。对于长时间操作,请使用带延迟的 WorkManager 或 viewModelScope 中的协程。不要释放 ViewModel 资源 — ViewModel 在 onStop 后仍然存在,返回时将被使用。

onStop 和 onPause 的区别

onPause 和 onStop 在可见性丧失的程度和必要操作的量上有所不同。onPause 在部分失去焦点时调用(例如打开对话框或系统菜单),onStop — 在完全失去可见性时。这种区别对于选择在每个阶段释放哪些资源非常重要。

特征onPauseonStop
可见程度部分可见完全不可见
焦点已失去已失去
执行时间最多 500 毫秒最多 5 秒(ANR 超时)
要释放的资源关键的(媒体、摄像头)所有不可见的(传感器、动画、位置)
恢复onResumeonRestart → onStart → onResume
进程优先级高(前台)中(后台)

一般规则:在 onPause 中,释放 立即影响其他应用程序用户体验的系统资源(摄像头、媒体播放器),在 onStop 中 — 释放隐藏 Activity 时不需要的所有其他资源。Google 建议在 onPause 中保存关键用户数据(电子邮件草稿、设置),因为在快速切换时可能不会调用 onStop。

onStop → onRestart:返回屏幕

当用户返回到隐藏的 Activity 时,系统调用 onRestart → onStart → onResume。onRestart 方法表示 Activity 正在从 Stopped 状态返回。这是恢复 UI 和在 onStop 中释放的资源的重要阶段。

返回时的调用序列:

  • onRestart() — Activity 被告知将再次显示。典型操作:重新加载数据、更新列表。
  • onStart() — Activity 变为可见,但尚未激活。在此处重新初始化在 onStop 中释放的资源。
  • onResume() — Activity 获得焦点并准备进行交互。动画启动,传感器注册。

如果应用程序进程在 Stopped 状态下被系统杀死,则调用 onCreate 而不是 onRestart,并且从 onSaveInstanceState 获得的 Bundle 被传递用于恢复状态。这种情况(process death)— 是 Android 应用程序中最常见的错误原因之一:开发人员实现了 onRestart,但忘记考虑进程杀死后通过 onCreate 的恢复。

Kotlin 中 onStop 的代码示例

示例 1:释放传感器的基本 onStop 实现

演示了在隐藏 Activity 时正确注销传感器和停止动画。返回屏幕后,资源在 onStart 中恢复。

kotlin
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 返回后,资源被重新创建。

示例 2:通过 SavedStateHandle 保存状态的 onStop

使用 ViewModel + SavedStateHandle 的现代方法。表单数据在 onStop 时自动保存,无需手动 Bundle。

kotlin
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。

示例 3:用于 onStop 中操作的 lifecycleScope

使用带有协程的 lifecycleScope 在进入 onStop 时异步保存数据。协程在 IO 调度器中启动,不会阻塞主线程。

kotlin
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 和 onDestroy 有什么区别?

onStop — Activity 变得不可见,但保留在 Stopped 状态的内存中。系统可以通过 onRestart 恢复 Activity。onDestroy — Activity 被销毁,内存被释放。onDestroy 之后,只能通过创建新的 Activity 实例(onCreate)来返回。

必须调用 super.onStop() 吗?

是的,必须调用。super.onStop() 确保系统组件(Fragment、LoaderManager、ViewModelStore)的正确运行。跳过 super.onStop() 可能导致内存泄漏和 Fragment 恢复不正确。始终最后或最先调用 super.onStop() — 顺序不重要,但调用是必需的。

如何检查 onStop 是否被调用?

在每个生命周期方法中使用 Log.dTimber。按 Activity 的标签启用 logcat 过滤器。对于生产环境,使用 Android Vitals — Google 自动收集生命周期指标并在 Play 控制台中显示异常。还可以通过 ProcessLifecycleOwner 进行生命周期监控。

如果在 onStop 中抛出异常会发生什么?

onStop 中未捕获的异常会导致应用程序 强制关闭。系统不会捕获生命周期回调中的异常。如果在 onStop 中执行可能抛出异常的操作(文件操作、网络),请将它们包装在 try-catch 中并记录错误,不要中断 super.onStop() 的执行。

是否需要在 onStop 中释放 Bitmap?

不需要,如果没有引用,Activity 中的 Bitmap 将由 GC 回收。在 onStop 中强制释放(recycle())不是必需的,甚至是有害的 — 如果 Activity 通过 onRestart 返回,则需要重新加载 Bitmap。使用 Glide 或 Coil 加载图像 — 这些库自动管理缓存和生命周期。

总结

  • onStop — Activity 的生命周期方法,在完全失去可见性时调用。Activity 保留在内存中,处于 Stopped 状态。
  • onStop 之后有两种可能的情况:onRestart(返回屏幕)或 onDestroy(销毁 Activity)。
  • 在 onStop 中,释放传感器、动画、摄像头、位置监听器 — Activity 不可见时不需要的所有内容。
  • onStop 与 onPause 的区别在于可见性程度:onPause — 部分丧失,onStop — 完全丧失可见性。
  • onSaveInstanceState 在 onStop 之前调用 — 使用它保存临时 UI 状态。
  • 带有 Dispatchers.IO 的 lifecycleScope 协程 — 在 onStop 中执行异步操作的首选方式。
  • 始终调用 super.onStop(),并将危险操作包装在 try-catch 中以避免强制关闭。

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

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

讨论项目

另请阅读