Activity生命周期:掌握onCreate、onStart、onResume、onPause、onStop、onDestroy的调用时机与场景
说实话,Activity生命周期这个话题,几乎是每个Android开发者入行时最先接触的概念。但有意思的是,我面试过不少自称“三年经验”的候选人,聊到生命周期细节时,往往只能背出六个方法名,真要问“onPause和onStop到底谁先谁后?什么场景下会只走onPause不走onStop?”就卡壳了。
嗯,今天咱们就把这六个回调方法彻底掰扯清楚。我会结合自己这些年踩过的坑,帮你建立起一套“肌肉记忆”——以后写代码时,不用查文档也能条件反射地知道该在哪个生命周期里做什么事。
一、生命周期全景图:六个回调,三种状态
先看一张我手绘的流程图,把整个生命周期串起来。你想想看,一个Activity从创建到销毁,就像一个人的一生:出生、成长、工作、暂停、休眠、离世。每个阶段都有对应的回调方法。
这张图我建议你保存下来。每次写Activity时瞄一眼,心里就有数了。我个人习惯把这张图打印出来贴在工位上,带新人时直接指着图讲,比说一万句都管用。
二、逐个击破:每个回调的“前世今生”
1. onCreate() —— 出生证明
这是Activity的“第一声啼哭”。系统创建Activity时调用,且只调用一次。说白了,这里就是做初始化工作的最佳场所。
典型用途:
- 调用 setContentView() 加载布局
- 初始化 View 引用(findViewById)
- 初始化 ViewModel、LiveData 等架构组件
- 恢复 savedInstanceState 中的状态
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 恢复状态
if (savedInstanceState != null) {
String userName = savedInstanceState.getString("user_name");
// 恢复用户输入等
}
// 初始化ViewModel
mViewModel = new ViewModelProvider(this).get(MyViewModel.class);
}
我的经验:千万别在onCreate里做耗时操作!我记得有一次接手一个老项目,前任在onCreate里直接做了网络请求,结果每次旋转屏幕都要等两三秒。后来改成在onResume里触发加载,配合缓存,体验好多了。
2. onStart() —— 准备登场
Activity从“不可见”变为“可见”时调用。注意,此时Activity虽然可见,但还不能与用户交互。嗯,你可以理解为演员已经站到了舞台上,但幕布还没拉开。
我在项目中遇到过一个问题:有个页面需要在显示时刷新数据,我一开始写在onResume里,结果每次从别的Activity返回都会刷新,太频繁了。后来改成在onStart里做,配合一个“是否需要刷新”的标记位,完美解决。
3. onResume() —— 正式开演
Activity进入前台,可以与用户交互了。这是用户真正“使用”你的页面的时刻。
典型用途:
- 开始动画、视频播放
- 注册广播接收器、传感器监听
- 打开相机预览
@Override
protected void onResume() {
super.onResume();
// 开始播放视频
if (mVideoView != null && !mVideoView.isPlaying()) {
mVideoView.start();
}
// 注册定位监听
mLocationManager.requestLocationUpdates(...);
}
注意:onResume和onPause是成对出现的。你想想看,如果用户在玩游戏时突然来电话,游戏画面应该暂停——这就是onPause要做的事。我曾经在做一个直播App时,忘记在onPause里停止摄像头预览,结果用户切到后台后摄像头还在亮着,被用户投诉“偷拍”……
4. onPause() —— 暂停时刻
当另一个Activity(比如来电界面、系统弹窗)覆盖当前Activity时调用。此时Activity仍然部分可见,但已经失去焦点。
关键点:onPause的执行时间非常短(Android官方建议在几百毫秒内完成),因为新Activity要等onPause执行完才能启动。所以,不要在onPause里做耗时操作。
避坑指南:我曾经在onPause里做数据库写入操作,结果导致新Activity启动卡顿。后来把数据保存挪到onStop里做,或者用WorkManager异步处理,流畅多了。
5. onStop() —— 退居幕后
Activity完全不可见时调用。比如用户按了Home键,或者启动了新的全屏Activity。
这里有个容易混淆的点:onPause和onStop的区别。说白了,onPause是“部分可见”,onStop是“完全不可见”。举个例子:
- 来电弹窗(非全屏)→ 只走onPause,不走onStop
- 按Home键 → 先onPause,再onStop
- 启动新全屏Activity → 先onPause,再onStop
典型用途:
- 保存草稿、持久化数据
- 停止动画、释放资源
- 注销广播接收器
6. onDestroy() —— 最后的告别
Activity被销毁前调用。可能是用户主动finish(),也可能是系统为了回收内存而销毁。
重要提醒:系统可能不会调用onDestroy!比如用户强制杀进程、系统内存极度紧张时,Activity可能直接被“处决”,连个招呼都不打。所以,不要把关键数据的保存放在onDestroy里。我习惯在onStop里做最后的保存工作,至少保证用户离开页面时数据是安全的。
@Override
protected void onDestroy() {
super.onDestroy();
// 清理资源
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
// 取消异步任务
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();
}
}
三、生命周期组合拳:常见场景分析
| 场景 | 回调顺序 | 说明 |
|---|---|---|
| 首次启动Activity | onCreate → onStart → onResume | 标准启动流程 |
| 按Home键回到桌面 | onPause → onStop | Activity进入后台 |
| 从桌面返回App | onRestart → onStart → onResume | 注意有onRestart |
| 按返回键退出 | onPause → onStop → onDestroy | 完整销毁流程 |
| 旋转屏幕(未配置configChanges) | onPause → onStop → onDestroy → onCreate → onStart → onResume | Activity重建 |
| 来电(非全屏弹窗) | onPause → onResume | 只暂停,不停止 |
你看,不同的场景下,生命周期的调用顺序是不一样的。我个人建议你写一个Demo,在每个回调里打Log,然后各种操作都试一遍——按Home键、旋转屏幕、接电话、启动新Activity……亲眼看到Log输出,比背十遍都管用。
四、实战中的“潜规则”
说几个我踩过的坑,希望能帮你少走弯路:
- onSaveInstanceState 不是生命周期方法,但它和onPause、onStop配合使用。系统会在Activity可能被销毁前调用它,让你保存临时状态。注意,它只在“非用户主动销毁”时调用——比如旋转屏幕、系统回收内存。用户按返回键时不会调用。
- onRestart 容易被忽略。当Activity从不可见变为可见时,如果之前已经onStop过,会先走onRestart再走onStart。我习惯在onRestart里做一些“恢复现场”的工作,比如重新加载列表数据。
- Fragment的生命周期比Activity更复杂。但核心逻辑是一样的——onCreate、onStart、onResume、onPause、onStop、onDestroy。只是多了onCreateView、onViewCreated等与视图相关的方法。
我的小技巧:写一个BaseActivity,把常用的生命周期逻辑封装好。比如在onPause里统一取消网络请求,在onResume里统一注册广播。这样所有子类都不用重复写这些代码了。我现在的项目里,BaseActivity大概有200行,全是生命周期相关的“防御性代码”。
五、总结:记住这三句话
好了,说了这么多,其实核心就三句话:
- onCreate做初始化,onDestroy做清理——这是“一生一次”的配对
- onResume开始工作,onPause暂停工作——这是“前台后台”的切换
- onStart准备登场,onStop退居幕后——这是“可见不可见”的分界
把这六兄弟的关系理清楚,你的Activity代码至少能少一半的bug。下次写代码时,多问自己一句:“这个操作放在哪个生命周期里最合适?”久而久之,你也会形成自己的“生命周期直觉”。
嗯,今天就聊到这儿。记住,生命周期不是背出来的,是用出来的。打开你的IDE,写个Demo跑一遍,比看十篇文章都管用。
公众号:蓝海资料掘金营,微信deep3321