冷启动首帧耗时采集框架

完整的冷启动首帧耗时采集框架,既支持:

  • 日常埋点(轻量、主流程);
  • 调试分析(高精度、开发模式);
  • 自动化集成(无侵入、支持主进程判断、多 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() 可选的高精度帧耗时采集(用于调试)

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