3、Activity与生命周期:Activity的创建、启动、销毁,以及onCreate、onStart、onResume、onPause、onStop、onDestroy回调详解。
各位同学,咱们今天来聊聊Android开发里最基础、也最绕不开的一个话题——Activity的生命周期。
说实话,我刚开始学Android那会儿,觉得这玩意儿不就是几个回调方法嘛,背下来就行了。直到后来线上出了个诡异的Bug,用户反馈说“App切到后台再回来,数据丢了”。我排查了半天,最后发现是生命周期没处理好。嗯,从那以后,我再也不敢小看这几个回调了。
你想想看,Activity就像是你App里的一个“页面管理员”。它什么时候出生、什么时候上班、什么时候摸鱼、什么时候下班,都得有一套规矩。这套规矩,就是生命周期。
3.1 Activity是什么?
简单说,Activity就是一个用户界面的容器。它负责展示UI,并处理用户的交互事件。每个Activity对应一个屏幕(或者一个浮层)。
我个人习惯把Activity比作“舞台”。你写的布局文件就是舞台上的布景,而生命周期回调就是舞台监督的指令——开灯、拉幕、演员上场、谢幕、关灯。
核心要点:Activity是Android四大组件之一,是用户与App交互的入口。每个Activity在AndroidManifest.xml中注册后才能使用。
3.2 生命周期回调详解
Android系统为了管理Activity的状态,定义了6个核心回调方法。它们按固定顺序执行,形成一个完整的生命周期。
先看一张流程图,我亲手画的,帮你理清这6个方法的调用顺序和对应状态:
这张图你看懂了吗?从上到下是Activity从创建到销毁的完整路径。虚线表示用户操作后重新进入的路径。说白了,这就是Activity的一生。
3.3 六个回调方法,逐个击破
3.3.1 onCreate() —— 出生
这是Activity生命周期的起点。系统创建Activity时调用,且只调用一次。
在这里,你应该做这些事:
- 调用 setContentView() 加载布局
- 初始化 View 和成员变量
- 绑定 Adapter、设置监听器
- 恢复之前保存的状态(从 Bundle 中读取)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 恢复之前保存的状态
if (savedInstanceState != null) {
String userName = savedInstanceState.getString("user_name");
// 恢复数据...
}
// 初始化控件
mTextView = findViewById(R.id.tv_hello);
mButton = findViewById(R.id.btn_click);
mButton.setOnClickListener(v -> {
// 处理点击事件
});
}
我的经验:onCreate里不要做耗时操作。我曾经在一个项目里直接在onCreate里加载网络数据,结果导致启动白屏好几秒。后来把网络请求挪到了onStart里,配合Loading动画,体验好多了。
3.3.2 onStart() —— 准备上台
Activity即将变得可见,但还不能与用户交互。说白了,就是“幕布刚拉开,演员还没就位”。
适合在这里做的事:
- 注册广播接收器
- 绑定Service
- 开始一些轻量级的动画
3.3.3 onResume() —— 正式演出
Activity变得可见且可交互。用户终于可以点按钮、滑动列表了。
注意:onResume是生命周期里最“活跃”的状态。用户每次回到这个Activity,都会走onResume。
@Override
protected void onResume() {
super.onResume();
// 开始轮询、开启传感器监听等
startLocationUpdates();
}
避坑指南:我曾经在onResume里忘记调用super.onResume(),结果导致Fragment的动画全部失效。找了半天才发现是这个问题。记住:super方法一定要调,而且要在你写逻辑之前调。
3.3.4 onPause() —— 暂停
Activity即将失去焦点,但依然可见。比如弹出了一个Dialog,或者用户按了Home键。
这里适合做:
- 保存未持久化的数据(比如草稿)
- 停止动画
- 释放一些系统资源
重要:onPause的执行时间非常短(Android 12之前是500ms,之后是100ms)。所以千万别在这里做耗时操作,比如网络请求、数据库写入。
3.3.5 onStop() —— 退到后台
Activity完全不可见了。用户打开了另一个App,或者按了返回键。
适合做的事:
- 取消网络请求
- 注销广播接收器
- 释放大内存对象(比如Bitmap)
@Override
protected void onStop() {
super.onStop();
// 取消网络请求
if (mCall != null && !mCall.isCanceled()) {
mCall.cancel();
}
// 注销广播
unregisterReceiver(mReceiver);
}
3.3.6 onDestroy() —— 谢幕
Activity被销毁了。可能是用户主动finish(),也可能是系统为了回收内存而杀掉它。
在这里,你需要清理所有资源:
- 关闭数据库连接
- 解绑Service
- 停止后台线程
核心原则:你在onCreate里创建了什么,就在onDestroy里销毁什么。一一对应,不要漏。
3.4 生命周期完整调用顺序
咱们用表格总结一下,不同场景下回调的调用顺序:
| 场景 | 调用顺序 |
|---|---|
| 首次启动Activity | onCreate → onStart → onResume |
| 按Home键回到桌面 | onPause → onStop |
| 从桌面回到Activity | onRestart → onStart → onResume |
| 按返回键退出 | onPause → onStop → onDestroy |
| 屏幕旋转(未配置configChanges) | onPause → onStop → onDestroy → onCreate → onStart → onResume |
| 被系统回收后重新创建 | onCreate(带savedInstanceState)→ onStart → onResume |
你发现没有?屏幕旋转会导致Activity销毁重建。这是Android早期设计的一个“坑”。我个人习惯在AndroidManifest里配置 android:configChanges="orientation|screenSize" 来避免不必要的重建,但前提是你自己能处理好配置变化。
3.5 实战中的避坑指南
讲了这么多理论,咱们来点实际的。我在项目中踩过的坑,分享给你:
- 不要在onPause里做耗时操作——系统会等onPause执行完才显示下一个Activity。你拖得越久,用户感觉越卡。
- onSaveInstanceState和onRestoreInstanceState——系统回收Activity时,会调用onSaveInstanceState保存数据。你需要在onCreate或onRestoreInstanceState里恢复。记住:这个方法只在Activity被“非正常”销毁时才会调用。用户按返回键正常退出,不会触发。
- Handler和内部类导致的内存泄漏——如果你在Activity里创建了Handler,并且发了一个延迟消息,在Activity销毁时消息还没处理,那这个Handler会持有Activity的引用,导致Activity无法被GC回收。解决办法:在onDestroy里移除所有消息和回调。
@Override
protected void onDestroy() {
super.onDestroy();
// 移除所有消息和回调,防止内存泄漏
mHandler.removeCallbacksAndMessages(null);
}
我曾经踩过的坑:有一个版本上线后,用户反馈说“App切到后台再切回来,页面数据全没了”。我查了半天,发现是因为在onStop里清空了列表数据,但没有在onStart里重新加载。后来我改成了:只在onDestroy里清数据,onStop里只暂停刷新,onStart里恢复刷新。问题解决了。
3.6 小结
Activity的生命周期,说白了就是一套“状态机”。系统通过这6个回调,告诉你Activity当前处于什么状态,以及接下来要进入什么状态。
你不需要死记硬背每个回调的调用顺序。你只需要记住一个原则:轻量、对称、及时。
- 轻量:每个回调里不要做耗时操作
- 对称:onCreate对应onDestroy,onStart对应onStop,onResume对应onPause
- 及时:该释放的资源及时释放,该保存的数据及时保存
做到这三点,你的Activity就不会出大问题。
公众号:蓝海资料掘金营,微信deep3321