1. 热启动与冷启动的定义与区别
移动应用的启动过程直接决定用户的第一印象。冷启动(Cold Start)与热启动(Hot Start)是两种截然不同的启动路径,其耗时差异可达数倍甚至数十倍。理解二者的本质区别,是进行启动优化的前提。本章从流程、耗时、触发场景三个维度拆解这两种启动模式,并给出可量化的对比基准。
1.1 冷启动流程
冷启动指应用进程从未创建,系统需要从零开始拉起进程、加载资源并完成首帧渲染的完整过程。典型触发场景包括:应用安装后首次打开、系统重启后首次打开、被系统自动杀后台后的重新打开。
冷启动的完整链路如下:
- 系统创建进程 — Zygote 进程 fork 新进程,分配独立内存空间。
- 加载 Application — 创建 Application 实例,依次执行
attachBaseContext()和onCreate()。 - 创建 MainActivity — 反射创建入口 Activity 实例,执行构造方法。
- 执行 onCreate() — 调用
setContentView()加载布局,执行findViewById()等初始化逻辑。 - 执行 onStart() / onResume() — 界面进入前台,开始渲染准备。
- 首帧绘制 — Choreographer 触发首次 VSYNC,完成首帧渲染并显示到屏幕。
冷启动耗时核心:第 2 步 Application.onCreate() 和第 4 步 Activity.onCreate() 是开发者可控的最大耗时区间。第三方 SDK 初始化、I/O 读写、布局解析都堆积在此。
1.2 热启动流程
热启动指应用进程已存在且 Activity 实例被保留在后台,用户重新将其切换到前台的过程。典型触发场景包括:按下 Home 键后再点击应用图标、从最近任务列表切回应用。
热启动的完整链路如下:
- Activity 恢复 — 系统调用
onRestart()(若已 stop)或直接走onStart()。 - 执行 onStart() — 界面可见性恢复,进行轻量状态恢复。
- 执行 onResume() — 界面获取焦点,恢复动画、传感器等资源。
- 界面可用 — 无需重新加载布局和资源,直接显示原有 UI。
关键差异:热启动不重建进程、不重新加载 Application、不重新解析布局。其主要开销在 Activity 生命周期恢复和少量内存重置,因此耗时远低于冷启动。
1.3 两者性能差异对比
下表从多个维度定量对比冷启动与热启动的差异:
| 对比维度 | 冷启动 | 热启动 |
|---|---|---|
| 进程状态 | 进程不存在,需新建 | 进程存活,活动已暂停 |
| 典型耗时 | 500 ms ~ 5 s(视应用复杂度) | 50 ms ~ 300 ms |
| 触发场景 | 首次安装 / 杀后台 / 系统重启 | Home 切出 / 最近任务切回 |
| 关键瓶颈 | 进程创建、Application 初始化、布局加载 | Activity 生命周期恢复、内存重置 |
| 优化重点 | 预初始化、按需加载、异步化 | 保持活动状态、减少恢复开销 |
| 可优化空间 | 较大(数百 ms ~ 数 s) | 较小(数十 ms) |
TTI(Time To Interactive)是衡量启动性能的黄金指标,定义为从用户点击图标到首帧完全渲染且可交互的时间。业界基准:冷启动 TTI ≥ 1 s,热启动 TTI ≤ 200 ms。
开发者可通过 am start -W 命令获取 Activity 启动的精确耗时,区分冷热启动场景:
# 冷启动测量:先强杀进程再启动
adb shell am force-stop com.example.app
adb shell am start -W -n com.example.app/.MainActivity | grep TotalTime
# 热启动测量:先按 Home 键再启动
adb shell input keyevent 3
adb shell am start -W -n com.example.app/.MainActivity | grep TotalTime
命令输出的 TotalTime 即为从启动到首帧完成的毫秒数。同一应用在冷热启动下的 TotalTime 数值差异通常在 5~20 倍之间。
1.4 冷启动 vs 热启动流程对比
下图为冷启动(左侧)与热启动(右侧)从用户点击到界面可用的完整路径对比。蓝色链路代表冷启动,绿色链路代表热启动,紫色为共同终点。黄色说明框标注了两者的典型耗时区间。