冷启动 vs 温启动 vs 热启动:三种启动模式的定义、差异与优化侧重点

做相机启动优化,第一个要搞清楚的,就是你的App到底是从哪种状态启动的。

我见过不少开发同学,上来就闷头优化,结果测了半天数据,发现测的根本不是同一个场景。冷启动、温启动、热启动,这三者的耗时差异可能差出好几倍。你想想看,如果连起点都没对齐,优化方向怎么可能对?

1. 三种启动模式的定义

我们先说清楚,这三种模式到底是什么意思。

冷启动

冷启动,说白了就是App进程还没创建,系统从零开始加载。用户点开相机图标,系统需要先fork一个进程,加载Application,创建主线程,然后一路跑到你的MainActivity。

这个过程中,系统要做的事情非常多:加载类、初始化资源、创建各种单例对象。我个人习惯把冷启动叫做「裸奔启动」——因为没有任何缓存可以利用。

冷启动的关键特征:

  • 进程不存在,需要重新创建
  • Application对象需要重新初始化
  • 所有类需要重新加载
  • 没有任何缓存数据可用
  • 耗时最长,通常在1-5秒甚至更久

温启动

温启动介于冷热之间。进程还在,但Activity被销毁了。比如用户按了返回键退出相机,但系统还没来得及杀掉进程。这时候再打开相机,进程还在,Application不用重新初始化,但Activity需要重新创建。

嗯,这里要注意:温启动时,虽然进程活着,但很多资源可能已经被回收了。比如图片缓存、一些单例对象,可能已经被GC干掉了。

我的一点经验:温启动在实际测试中很容易被忽略。很多团队只盯着冷启动数据,结果上线后发现用户反馈「打开相机好慢」。其实用户日常使用中,温启动才是最常见的场景。

热启动

热启动是最理想的情况。进程活着,Activity也活着,只是被系统暂停了。比如用户按了Home键,然后马上又切回来。这时候Activity甚至不需要重新创建,只需要调用onResume就行。

热启动的耗时通常只有几百毫秒,甚至几十毫秒。说白了,就是恢复一下状态,刷新一下UI。

热启动的关键特征:

  • 进程存活
  • Activity实例存活
  • 不需要重新创建任何对象
  • 只需要恢复状态和刷新UI
  • 耗时最短,通常在100-300ms

2. 三种模式的差异对比

光说定义可能还不够直观。我整理了一张对比表,你可以直接拿去用。

对比维度 冷启动 温启动 热启动
进程状态 不存在 存活 存活
Application 重新初始化 无需初始化 无需初始化
Activity 重新创建 重新创建 恢复状态
类加载 全部重新加载 部分缓存 全部缓存
典型耗时 1-5s 500ms-2s 100-300ms
优化空间 最大 中等 较小

从这张表能看出来,冷启动的优化空间最大,但也是最难啃的骨头。温启动和热启动的优化,更多是锦上添花。

3. 核心逻辑流程图

为了让你更直观地理解这三种启动模式的流转关系,我画了一张图。

三种启动模式核心逻辑流程图 用户点击相机图标 进程是否存在? (判断点) 冷启动 创建进程+Application Activity是否存在? (判断点) 热启动 恢复Activity状态 温启动 重建Activity 相机界面显示完成 耗时:1-5s 耗时:500ms-2s 耗时:100-300ms

从这张图可以看得很清楚:冷启动走的是最长的路径,温启动省去了进程创建,热启动则几乎什么都不用做。

4. 优化侧重点

搞清楚了定义和差异,接下来才是重点——怎么优化?

冷启动优化:重灾区

冷启动的优化,说白了就是「能省则省,能懒则懒」。

  • Application初始化:把非必要的初始化放到后台线程,或者延迟到真正需要的时候再做。我曾经在一个项目里发现,Application的onCreate里居然在初始化一个第三方推送SDK,而这个SDK在相机场景里根本用不到。
  • 类加载优化:减少启动路径上的类加载数量。可以用App Startup库来做依赖管理,或者用字节码插桩来统计启动时加载的类。
  • 资源加载:避免在启动时加载大图或者复杂布局。我建议把相机预览的SurfaceView或者TextureView的创建延迟到onResume之后。
  • ContentProvider:检查一下你的AndroidManifest里注册了多少ContentProvider。每个ContentProvider在Application初始化时都会被创建,这玩意儿多了,启动时间直接翻倍。

避坑指南:我曾经在一个项目中,为了优化冷启动,把所有的初始化都丢到了后台线程。结果上线后出现了各种空指针异常——因为有些初始化是有依赖关系的。所以,延迟初始化一定要做好依赖管理,别为了快而牺牲稳定性。

温启动优化:容易被忽视的战场

温启动的优化,核心在于「减少重建成本」。

  • Activity重建优化:使用ViewModel来保存状态,避免因为Activity重建导致的数据丢失和重复加载。
  • 缓存策略:把一些重量级的对象(比如CameraManager、CameraDevice)做成单例,避免重复创建。
  • 布局复用:如果相机界面比较复杂,可以考虑用Fragment来承载核心逻辑,这样Activity重建时Fragment可以复用。

热启动优化:细节决定体验

热启动的优化空间不大,但做得好坏直接影响用户的第一印象。

  • onResume速度:检查onResume里有没有做耗时操作。我见过有人在onResume里做网络请求,这完全不应该。
  • 状态恢复:确保相机预览的恢复足够快。比如重新打开CameraDevice、重新创建CaptureSession,这些操作尽量异步执行。
  • 内存管理:热启动慢,很多时候是因为内存不足导致Activity被系统回收了。所以,做好内存优化,减少内存泄漏,也能间接提升热启动速度。

5. 如何区分和测量

最后,说说怎么在实际项目中区分这三种模式。

我个人的习惯是,在Application的onCreate和Activity的onCreate里打上日志,然后看日志的调用情况:

// 冷启动:Application.onCreate 和 Activity.onCreate 都会调用
// 温启动:只有 Activity.onCreate 调用,Application.onCreate 不调用
// 热启动:两个都不调用,只有 Activity.onResume 调用

用这个办法,你可以很清楚地知道当前测试的是哪种模式。另外,我建议你在做性能测试时,三种模式都要覆盖到,别只盯着冷启动。

小技巧:在测试冷启动时,可以用adb命令杀掉进程再启动:adb shell am force-stop com.yourapp.package。测试温启动时,按返回键退出再重新打开。测试热启动时,按Home键再切回来。

好了,三种启动模式的定义、差异和优化侧重点,到这里就讲清楚了。下一节我们会深入冷启动的细节,看看从点击图标到第一帧画面,中间到底发生了什么。


公众号:蓝海资料掘金营,微信deep3321