onResume — 是Android生命周期方法,当Activity或Fragment进入前台并获得输入焦点时被调用。在此状态下,屏幕已准备好与用户交互:所有触摸事件、按键和手势都定向到此组件。onResume是Activity的工作状态,应用程序大部分时间都在此状态中度过。正是在这里打开相机、启动视频播放、开始语音识别并注册需要独占访问的传感器监听器。有关Activity完整生命周期的更多信息,请阅读文章Activity Lifecycle。
要点
onResume — 是Activity生命周期的第三个方法,在onStart之后调用,表示屏幕已准备好与用户完全交互. 此时,Activity位于任务栈(back stack)的顶部,系统将所有输入事件定向到它,应用程序可以开始任何需要用户积极参与的操作:视频通话、游戏、录音、在Canvas上绘图。
onResume属于前台生命周期(foreground lifetime)— 即onResume和onPause之间的时间间隔。这是Activity最活跃的工作期,应用程序消耗最大资源:处理器处理触摸、GPU渲染动画、相机和麦克风用于视频捕获。理解这一生命周期级别对于优化能耗至关重要 — 在onResume中打开的资源必须在onPause中立即关闭。
根据Google I/O 2025的数据,Activity在一次会话中处于onResume状态的平均时间为新闻应用2–5分钟,游戏和即时通讯应用15–30分钟。其余时间Activity处于onPause、onStop或onDestroy状态。这意味着优化onResume代码能在性能和电池续航方面带来最大收益。
在Activity中,onResume方法在每次屏幕获得输入焦点时被调用 — 首次启动时、从其他Activity返回时、关闭对话框时、设备解锁时。这是一个热方法,可能在一次会话中被多次调用,其实现应尽可能轻量。
class CameraActivity : AppCompatActivity() {
private var cameraProvider: ProcessCameraProvider? = null
private var preview: Preview? = null
override fun onResume() {
super.onResume()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding?.viewFinder?.surfaceProvider)
}
try {
cameraProvider?.unbindAll()
cameraProvider?.bindToLifecycle(
this, cameraSelector, preview
)
} catch (e: Exception) {
Log.e("Camera", "绑定相机失败", e)
}
}, ContextCompact.getMainExecutor(this))
}
override fun onPause() {
super.onPause()
cameraProvider?.unbindAll()
preview = null
}
}
CameraX示例展示了onResume/onPause的经典用法:相机是一种独占资源,同一时间只能由一个应用程序使用。通过bindToLifecycle将相机绑定到生命周期会自动在onPause中关闭相机,但显式调用unbindAll可确保立即释放。这在Activity之间切换时尤为重要:相机必须在其他Activity尝试打开之前释放。
Fragment中的onResume在其包含的Activity收到onResume后被调用. 但由于FragmentManager和ViewPager的特性,Fragment的onResume调用时刻可能相对于Activity延迟。例如,在offscreenPageLimit = 1的ViewPager中,Fragment只有在成为当前页面时才收到onResume,而不是在Activity启动时。
class VideoPlayerFragment : Fragment() {
private var exoPlayer: ExoPlayer? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
exoPlayer = ExoPlayer.Builder(requireContext()).build()
binding?.playerView?.player = exoPlayer
}
override fun onResume() {
super.onResume()
exoPlayer?.play()
if (userVisibleHint) {
startBiometricAuth()
}
}
override fun onPause() {
exoPlayer?.pause()
stopBiometricAuth()
super.onPause()
}
}
检查Fragment.onResume中的userVisibleHint对于ViewPager是必要的:Fragment可能收到onResume但被相邻页面隐藏(例如,在动画过渡期间)。在这种情况下,在onResume中启动视频或生物识别而不检查可见性将导致意外行为。从Fragment 1.5.0开始,建议使用FragmentTransaction.setMaxLifecycle()精确控制ViewPager2中片段的生命周期。
开发人员经常混淆onStart和onResume,将代码放在错误的方法中。主要规则:onStart — 用于在可见性下工作的资源; onResume — 用于需要输入焦点的资源. 让我们看看具体场景和方法的选择。
| 操作 | 方法 | 理由 |
|---|---|---|
| 订阅地理位置 | onStart / onStop | GPS在部分可见性下可以工作 |
| 打开相机 | onResume / onPause | 相机 — 独占资源 |
| BroadcastReceiver | onStart / onStop | 系统事件不需要焦点 |
| 视频播放 | onResume / onPause | 视频必须对用户可见 |
| 蓝牙扫描 | onStart / onStop | 扫描可以在后台继续 |
| 录音机(MediaRecorder) | onResume / onPause | 录音需要活跃的UI |
| 传感器监听器 | onResume / onPause | 用于游戏和手势的传感器 |
| 数据更新 | onStart | 出现时需要新鲜数据 |
实用规则:如果操作应在对话框出现时中断 — 使用onResume/onPause。如果操作可以在屏幕部分覆盖时继续 — 使用onStart/onStop。例如,视频播放器应在打开对话框时暂停视频(onPause),而地理位置可以继续更新(保持在onStart)。
独占资源是设备组件,在特定时刻只能由一个应用程序使用. 相机、麦克风、视频输出(MediaProjection)、读取模式下的NFC适配器、配件模式下的USB设备 — 所有这些资源必须在onResume中打开并在onPause中释放。
MediaRecorder用于录制音频和视频. 请求权限和准备MediaRecorder在onCreate中完成,开始录制在onResume中。如果用户切换到其他应用程序,onPause暂停录制,onResume恢复录制。这是录音机和视频录制应用程序的标准行为。
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
override fun onResume() {
super.onResume()
if (isRecording) {
mediaRecorder?.resume()
}
}
override fun onPause() {
if (isRecording) {
mediaRecorder?.pause()
}
super.onPause()
}
生物识别认证(BiometricPrompt)只应在Activity处于onResume状态时调用. 如果在onCreate或onStart中调用,生物识别对话框可能在Activity完成初始化之前出现,导致结果处理不正确。在onResume中调用确保生物识别窗口在正确的上下文中显示。
让我们看看onResume工作的三种经过验证的模式,这些模式应用于商业项目:重置不活动计时器、更新可见数据以及与Jetpack Navigation集成。
在具有机密数据的应用程序中(银行、医疗卡)onResume用于重置自动退出计时器. 如果用户积极与应用程序交互,onResume在每次屏幕切换时被调用,计时器重置。如果用户最小化应用程序,onPause停止计时器,返回时onResume要么重置它,要么要求重新认证。
应在每次返回屏幕时显示最新数据的列表在onResume中更新. 例如,如果用户在另一个Activity中创建了新记录并返回,onResume从本地数据库或ViewModel缓存重新加载列表。这确保了数据的一致性,无需手动调用notifyDataSetChanged。
override fun onResume() {
super.onResume()
// ActivityResultLauncher返回了结果 — 更新列表
viewModel.refreshList()
// 重置不活动计时器
inactivityTimer.reset()
}
在Jetpack Navigation中,片段的onResume在通过返回导航每次回到它时被调用. 此属性用于重置UI状态:隐藏键盘、清除搜索字段、更新工具栏标题。OnBackPressedCallback与onResume结合提供对导航的完全控制,无需重复代码。
常见问题
onStart — 屏幕可见。onResume — 屏幕活跃并准备好交互. 想象一下:你看电视(onStart),但把遥控器拿在手里(onResume)。电视总是可见的,但交互只有用遥控器才开始。如果有人用窗帘遮住电视 — 屏幕不再可见(onStop)。如果遥控器被拿走 — 交互停止(onPause),但电视仍然可见。
onResume每次Activity获得输入焦点时被调用. 最少次数 — 一次(启动时)。最大次数取决于使用场景:屏幕之间切换、打开对话框、快速锁定和解锁设备 — 每个这样的场景在返回屏幕时都会调用onResume。
相机 — 独占资源,同一时间只对一个应用程序可用. 如果在onCreate或onStart中打开相机,即使您的应用程序不活跃,它也会被锁定,其他应用程序无法使用。onResume确保相机仅在Activity在前台时打开,而onPause立即关闭它。这是Android开发的标准,在CameraX和Camera2 API文档中有明确规定。
是的,如果Activity在出现后立即被另一个Activity覆盖,onResume可能不会发生. 例如,Activity A在onCreate或onStart方法中启动Activity B。在这种情况下,A收到onStart → onPause → onStop,跳过onResume。系统不调用onResume,因为Activity A从未获得输入焦点。
在onResume中不能执行长时间同步操作:从网络加载大量数据、复杂的SQL查询、图像处理。onResume方法在UI线程中运行,任何超过100–200毫秒的阻塞都会导致界面响应延迟。所有繁重操作都应该是异步的 — 通过协程、RxJava或WorkManager。也不建议在onResume中无检查地调用finish() — 这可能导致无限重建循环。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。