应用首帧耗时开始时间
应用首帧耗时的开始时间,在官方或业界标准里,是从系统启动应用进程的时间开始算起,也就是:
Zygote 进程 fork 出你的应用进程的时刻(冷启动场景)
更精准的定义
“应用首帧耗时” = 从系统启动应用进程 ➜ 到首个 Activity 完整绘制首帧(第一帧渲染完成)之间的耗时
这个定义适用于冷启动(cold start)场景,是用户真实体验中感知的“从点击图标 ➜ 到看到界面”的时间。
对应的系统级关键时间点
阶段 | 说明 | 是否可控 |
---|---|---|
1. 进程创建 | Zygote fork 出你的 app 进程(系统完成) | ❌ 不可控 |
2. Application 初始化 | 调用 Application.attach() ➜ onCreate() | ✅ 可记录 |
3. Activity 初始化 | 调用 Activity.onCreate() ➜ onResume() | ✅ 可记录 |
4. 首帧渲染完成 | 视图绘制并提交给 SurfaceFlinger | ✅ 可记录(Choreographer) |
如何在代码中还原“真实首帧耗时”?
虽然应用进程启动时你还不能打点,但你可以近似从 Application.attachBaseContext() 记录开始时间来做分析:
object LaunchTimeMonitor {
var launchStartTime = 0L
}
class App : Application() {
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
LaunchTimeMonitor.launchStartTime = SystemClock.elapsedRealtime()
}
}
- attachBaseContext() 是你能接触到的最早时机;
- 更早的时间点只能通过系统 trace 工具(如 Perfetto)获取。
如果你用的是Perfetto或Systrace
你能看到启动时间线中的这些标记:
[ActivityManager] Start proc: com.example.app for activity ...
[Choreographer] doFrame
你可以精确分析:
- fork → bindApplication(Application 创建)
- ActivityThread.main()
- Activity 生命周期
- 渲染提交时间
实际开发中常见折中方案
起始点选取 | 实际含义 | 精度 |
---|---|---|
Application.attachBaseContext() | 接近 fork 后启动点 | 最推荐 |
Application.onCreate() | 比上面略晚 | 可接受 |
Activity.onCreate() | 太晚,已错过 Application 初始化 | 不推荐 |
总结
问题 | 答案 |
---|---|
应用首帧耗时从哪里开始算? | 从 Zygote fork 出你的进程那一刻 |
我们代码中怎么记录? | 最早从 Application.attachBaseContext() 开始 |
系统怎么测? | 通过 Perfetto / Systrace 追踪真实启动耗时 |