冷启动首帧耗时采集框架
完整的冷启动首帧耗时采集框架,既支持:
- 日常埋点(轻量、主流程);
- 调试分析(高精度、开发模式);
- 自动化集成(无侵入、支持主进程判断、多 Activity 兼容)。
目标
封装一个类 LaunchTimeTracer,具备以下功能:
功能 | 是否实现 |
---|---|
启动开始时间记录 | ✅ |
首帧完成时间记录 | ✅ |
高精度帧耗时监听(可选) | ✅ |
是否是主进程判断 | ✅ |
是否为冷启动判断 | ✅ |
自动 hook Application 和首个 Activity | ✅ |
数据上报或打印接口 | ✅ 可扩展 |
最终结构概览
object LaunchTimeTracer {
fun init(application: Application)
fun onFirstFrameDrawn()
}
实现代码(基础版 + 可选高精度监听)
1. LaunchTimeTracer.kt
object LaunchTimeTracer {
private var isColdStart = true
private var hasReported = false
private var startTime = 0L
private var reportBlock: ((duration: Long) -> Unit)? = null
fun init(application: Application, report: ((Long) -> Unit)? = null) {
reportBlock = report
if (!isMainProcess(application)) return
application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
if (isColdStart) {
startTime = SystemClock.elapsedRealtime()
}
}
override fun onActivityResumed(activity: Activity) {
if (isColdStart && !hasReported) {
activity.window.decorView.post {
Choreographer.getInstance().postFrameCallback {
val duration = SystemClock.elapsedRealtime() - startTime
hasReported = true
isColdStart = false
reportBlock?.invoke(duration)
Log.d("LaunchTimeTracer", "首帧耗时: ${duration}ms")
}
}
}
}
override fun onActivityDestroyed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
})
}
private fun isMainProcess(application: Application): Boolean {
val pid = Process.myPid()
val currentProcess = application.getSystemService(ActivityManager::class.java)
?.runningAppProcesses?.firstOrNull { it.pid == pid }
return application.packageName == currentProcess?.processName
}
}
使用方式
在你的 Application 中初始化:
class MyApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
LaunchTimeTracer.init(this) { cost ->
// 在这里做日志记录、埋点上报等
uploadLaunchDuration(cost)
}
}
}
可选:高精度帧耗时监听(开发调试用)
添加这段代码,可捕捉每一帧渲染的真实耗时:
@TargetApi(Build.VERSION_CODES.N)
fun Activity.traceFrameMetrics() {
window.addOnFrameMetricsAvailableListener({ _, metrics, _ ->
val total = metrics.getMetric(FrameMetrics.TOTAL_DURATION)
val draw = metrics.getMetric(FrameMetrics.DRAW_DURATION)
Log.d("FrameMetrics", "Total: ${total / 1_000_000}ms, Draw: ${draw / 1_000_000}ms")
}, Handler(Looper.getMainLooper()))
}
你可以在 onResume 中调试时调用:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
traceFrameMetrics()
}
总结
类 | 功能 |
---|---|
LaunchTimeTracer.init() | 自动检测主进程 + 注册回调 |
onActivityCreated() | 冷启动判定时机 |
onActivityResumed() + Choreographer | 捕捉首帧绘制前的回调 |
reportBlock | 可自定义上报逻辑 |
traceFrameMetrics() | 可选的高精度帧耗时采集(用于调试) |