文章目录
-
- 前言
- [1. 项目整体介绍](#1. 项目整体介绍)
-
- [Activity 职责一览](#Activity 职责一览)
- [2. Activity 生命周期概览](#2. Activity 生命周期概览)
- [3. 源码逐行解读](#3. 源码逐行解读)
-
- [3.1 MainActivity(核心)](#3.1 MainActivity(核心))
- [3.2 NormalActivity](#3.2 NormalActivity)
- [3.3 DialogActivity(对话框主题)](#3.3 DialogActivity(对话框主题))
- [3.4 布局文件](#3.4 布局文件)
- [3.5 AndroidManifest.xml](#3.5 AndroidManifest.xml)
- [4. 五种场景下的生命周期调用顺序](#4. 五种场景下的生命周期调用顺序)
-
- 场景一:应用正常启动
- 场景二:点击 "Start NormalActivity"
- [场景三:从 NormalActivity 按返回键](#场景三:从 NormalActivity 按返回键)
- 场景四:点击 "Start DialogActivity"
- [场景五:从 DialogActivity 按返回键](#场景五:从 DialogActivity 按返回键)
- [5. 关键知识点深度剖析](#5. 关键知识点深度剖析)
-
- [5.1 `onPause` vs `onStop` 的区别](#5.1
onPausevsonStop的区别) - [5.2 `onSaveInstanceState` 的作用](#5.2
onSaveInstanceState的作用) - [5.3 为什么在 `onCreate` 中恢复数据?](#5.3 为什么在
onCreate中恢复数据?) - [5.4 完整生命周期状态图](#5.4 完整生命周期状态图)
- [5.1 `onPause` vs `onStop` 的区别](#5.1
- [6. 总结](#6. 总结)
前言
对于每一位 Android 开发者来说,理解 Activity 的生命周期 是最基础也是最重要的入门知识。面试必问、开发必用、排查问题必备。
本文将借助一个Demo 项目 ------ ActivityLifeCycleTest ,通过 实际代码 + 日志验证 + 场景模拟 的方式,带你彻底搞懂 Activity 的 7 个生命周期方法和不同场景下的回调顺序。即使你是零基础的初学者,也能通过本文一步到位。
1. 项目整体介绍
| 项目属性 | 说明 |
|---|---|
| 项目名称 | ActivityLifeCycleTest |
| 语言 | Java + XML |
| Activity 数量 | 3 个 |
| 核心机制 | 每个 Activity 的 7 个生命周期方法都打上了 Log 日志 |
Activity 职责一览
| Activity | 主题 | 作用 |
|---|---|---|
MainActivity |
默认主题(全屏) | 入口页面,两个按钮分别启动另外两个 Activity |
NormalActivity |
默认主题(全屏) | 模拟启动普通 Activity 的场景 |
DialogActivity |
Theme.AppCompat.Dialog |
模拟启动对话框式 Activity 的场景 |
2. Activity 生命周期概览
Android 官方将 Activity 的生命周期划分为以下 7 个核心回调:
Activity 启动
│
▼
┌──────────┐
│ onCreate │ ← 首次创建,只调用一次
└────┬─────┘
▼
┌──────────┐
│ onStart │ ← Activity 即将可见
└────┬─────┘
▼
┌──────────────┐ ┌───────────────┐
│ onResume │◄────│ onRestart │
│ (前台可交互) │ │ (重新启动后) │
└──────┬───────┘ └───────▲───────┘
│ │
▼ │
┌──────────┐ │
│ onPause │ ── 再次可见 ──►│
└────┬─────┘
▼
┌──────────┐
│ onStop │ ← Activity 完全不可见
└────┬─────┘
▼
┌───────────┐
│ onDestroy │ ← Activity 被销毁
└───────────┘
生命周期方法速查表
| 方法 | 调用时机 | 调性 | 是否可被杀 |
|---|---|---|---|
onCreate() |
Activity 首次创建 | 整个生命周期只调一次 | ❌ |
onStart() |
Activity 即将可见(仍在后台) | 可调多次 | ❌ |
onResume() |
Activity 获得焦点,可交互 | 可调多次 | ❌ |
onPause() |
失去焦点,部分可见(如被对话框遮挡) | 可调多次 | ✅(Android 7.0+ 不再) |
onStop() |
完全不可见 | 可调多次 | ✅ |
onDestroy() |
Activity 被销毁前 | 只调一次 | ✅ |
onRestart() |
从 onStop 回到 onStart 时 |
可调多次 | ❌ |
3. 源码逐行解读
3.1 MainActivity(核心)
java
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate"); // 日志打点
setContentView(R.layout.activity_main);
// 如果 Activity 是被系统销毁后重建的,恢复保存的临时数据
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG, tempData); // 会打印 "Something you just typed"
}
// 按钮1:启动 NormalActivity
Button startNormalActivity = findViewById(R.id.start_normal_activity);
startNormalActivity.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, NormalActivity.class);
startActivity(intent);
});
// 按钮2:启动 DialogActivity
Button startDialogActivity = findViewById(R.id.start_dialog_activity);
startDialogActivity.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, DialogActivity.class);
startActivity(intent);
});
}
// 当 Activity 被系统意外销毁时,保存临时数据
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key", tempData);
}
// ========== 以下六个方法全部只打 Log ==========
@Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart"); }
@Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume"); }
@Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause"); }
@Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop"); }
@Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); }
@Override protected void onRestart() { super.onRestart(); Log.d(TAG, "onRestart"); }
}
代码要点解析
- TAG 常量 :定义
"MainActivity"为日志标签,可通过adb logcat -s MainActivity过滤只看该 Activity 的日志。 - onSaveInstanceState :这是非生命周期方法,用于系统销毁 Activity 前 保存临时状态(如用户输入)。当 Activity 被重建时,数据通过
onCreate(Bundle)中的savedInstanceState恢复。 - 两个按钮 :分别以普通 Intent 方式启动
NormalActivity和DialogActivity,用来观察不同目标 Activity 对 MainActivity 生命周期的影响。
3.2 NormalActivity
java
public class NormalActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.normal_layout);
}
}
这是最简单的 Activity 实现,仅覆写 onCreate 并加载布局。
注意 :它没有覆写 onPause、onStop 等生命周期方法,也没有打日志 ------ 但我们关注的是它对 MainActivity 生命周期的影响。
3.3 DialogActivity(对话框主题)
java
public class DialogActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_layout);
}
}
代码与 NormalActivity 几乎一样,关键在于 AndroidManifest 中的主题声明:
xml
<activity
android:name=".DialogActivity"
android:theme="@style/Theme.AppCompat.Dialog" />
Theme.AppCompat.Dialog 使 DialogActivity 以对话框样式显示,这意味着:
- MainActivity 在后台仍然部分可见
- MainActivity 只会走到
onPause,不会走到onStop
对话框式 Activity 并不会让前一个 Activity 完全不可见。
3.4 布局文件
activity_main.xml:
xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/start_normal_activity"
android:layout_width="277dp"
android:layout_height="141dp"
android:text="Start NormalActivity" />
<Button
android:id="@+id/start_dialog_activity"
android:layout_width="281dp"
android:layout_height="191dp"
android:text="Start DialogActivity" />
</LinearLayout>
两个大按钮,垂直排列,各自负责启动一个子 Activity。
normal_layout.xml / dialog_layout.xml:
xml
<LinearLayout ...>
<TextView
android:text="This is a normal activity" />
</LinearLayout>
简洁的占位提示文本,仅用于区分当前所处页面。
3.5 AndroidManifest.xml
xml
<activity
android:name=".DialogActivity"
android:theme="@style/Theme.AppCompat.Dialog"
android:exported="true" />
<activity
android:name=".NormalActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
| 配置项 | 说明 |
|---|---|
MainActivity → LAUNCHER |
应用启动入口 |
DialogActivity.theme="Theme.AppCompat.Dialog" |
对话框主题,关键差异 |
NormalActivity.exported="false" |
不允许外部应用启动 |
4. 五种场景下的生命周期调用顺序
以下是基于本 Demo 项目,通过 Logcat 实际验证 的调用顺序。
场景一:应用正常启动
MainActivity: onCreate
MainActivity: onStart
MainActivity: onResume
结论 :onCreate → onStart → onResume,这是每个 Activity 的"标准启动三部曲"。
场景二:点击 "Start NormalActivity"
MainActivity: onPause
NormalActivity: onCreate
NormalActivity: onStart
NormalActivity: onResume
MainActivity: onStop ← MainActivity 完全不可见
结论:
- 新 Activity 的
onResume在旧 Activity 的onStop之前完成,保证新界面先出现,用户体验流畅。 - 旧 Activity 进入
onPause→onStop,但没有被销毁。
场景三:从 NormalActivity 按返回键
NormalActivity: onPause
MainActivity: onRestart ← 注意!回到 MainActivity 调用的是 onRestart
MainActivity: onStart
MainActivity: onResume
NormalActivity: onStop
NormalActivity: onDestroy
结论:
- MainActivity 不是从
onCreate重新创建,而是从onRestart→onStart→onResume恢复。 - NormalActivity 被销毁:
onPause→onStop→onDestroy。
场景四:点击 "Start DialogActivity"
MainActivity: onPause ← 注意!只到 onPause
DialogActivity: onCreate
DialogActivity: onStart
DialogActivity: onResume
结论:
- MainActivity 仅走到
onPause,没有走到onStop! - 原因:DialogActivity 是对话框主题,MainActivity 仍然部分可见,所以不需要
onStop。
🔑 核心区分 :
onPause= 失去焦点但可能部分可见;onStop= 完全不可见。
场景五:从 DialogActivity 按返回键
DialogActivity: onPause
MainActivity: onResume ← 直接从 onPause 回到 onResume!
DialogActivity: onStop
DialogActivity: onDestroy
结论:
- MainActivity 从
onPause直接回到onResume,不会调用onRestart和onStart! - 因为 MainActivity 从未进入
onStop状态,所以恢复时走的是onPause → onResume的"快速恢复"路径。
关键区别 :
onStop → onRestart → onStart(完全可见恢复) vsonPause → onResume(部分可见恢复)。
5. 关键知识点深度剖析
5.1 onPause vs onStop 的区别
| 对比维度 | onPause | onStop |
|---|---|---|
| Activity 是否可见 | 部分/完全可见 | 完全不可见 |
| 触发场景 | 弹窗覆盖、新 Activity 半透明、分屏 | 新 Activity 全屏覆盖、按 Home 键 |
| 恢复路径 | onResume() |
onRestart() → onStart() → onResume() |
| 适合做的事情 | 暂停动画、停止摄像头预览 | 保存持久数据、释放重量级资源 |
5.2 onSaveInstanceState 的作用
java
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("data_key", "Something you just typed");
}
- 调用时机:Activity 即将被系统销毁但可能重建 时(如旋转屏幕、内存不足),在
onStop之前调用。 - 不调用时机:用户主动按返回键关闭 Activity 时不会调用。
- 恢复方式:在
onCreate(Bundle savedInstanceState)或onRestoreInstanceState(Bundle)中取出。
5.3 为什么在 onCreate 中恢复数据?
java
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG, tempData);
}
Demo 中在 onCreate 的 setContentView 之前判断并恢复 ------ 这样就可以在 UI 初始化之前准备好数据(比如填充 EditText 的内容)。
5.4 完整生命周期状态图
┌──────────────┐
首次启动 │ Activity │
─────────────► │ launched │
└──────┬───────┘
│ onCreate()
▼
┌──────────────┐
│ │
│ Created │◄──────────────────────────┐
│ │ │
└──────┬───────┘ │
│ onStart() │
▼ │
┌──────────────┐ │
│ Started │──── onRestart() ──────────┤
│ │ │
└──────┬───────┘ │
│ onResume() │
▼ │
┌──────────────────────────────────────────────┐ │
│ │ │
│ ┌──────────────┐ │ │
│ │ Resumed │◄──────── onResume() ───────┤ │
│ │ (可交互前台) │──────── onPause() ────────►│ │
│ └──────────────┘ ┌───────┴───────┐ │
│ │ Paused │ │
│ │ (部分可见) │ │
└──────────────────────────────────────┴───────┬───────┘ │
│ onStop() │
▼ │
┌──────────────┐ │
│ Stopped │──────┘
│ (不可见) │
└──────┬───────┘
│ onDestroy()
▼
┌──────────────┐
│ Destroyed │
│ (已销毁) │
└──────────────┘
6. 总结
我们从 理论 → 代码 → 日志验证 → 场景模拟 四个维度完整覆盖了 Android Activity 的生命周期:
- 7 个生命周期方法 的调用时机和顺序
- onPause 和 onStop 的本质区别(部分可见 vs 完全不可见)
- onSaveInstanceState 的数据保存与恢复机制
- 对话框式 Activity 对父 Activity 生命周期的特殊影响
掌握 Activity 生命周期,是写出稳定、流畅 Android 应用的第一步,也是迈向高级开发的必经之路。