应用首帧耗时开始时间

应用首帧耗时的开始时间,在官方或业界标准里,是从系统启动应用进程的时间开始算起,也就是:

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)获取。

如果你用的是PerfettoSystrace

你能看到启动时间线中的这些标记:

[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 追踪真实启动耗时

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器