3. 埋点需求分析
启动阶段的事情特别多,但埋点不能什么都打。我见过最夸张的项目,一个启动流程埋了三百多个点,最后分析时发现一半都是脏数据。所以,在动手写代码之前,先搞清楚一个问题:到底需要采集哪些数据?
说白了,这就是埋点的需求分析。你要把启动过程里的用户行为、系统状态、业务指标都拆开来看,然后给它们排个优先级。否则你采集了一大堆,最后发现关键的几个漏掉了。
3.1 启动阶段的数据分类
我个人习惯把启动阶段的数据分成四大类,你可以拿这个框架对照自己的项目。
| 类别 | 典型数据点 | 采集目的 |
|---|---|---|
| 系统环境数据 | 设备型号、Android版本、内存大小、存储空间、网络类型 | 判断启动慢是不是硬件或系统环境的问题 |
| 应用状态数据 | 安装来源、上次使用版本、是否冷启动、是否有缓存 | 区分首次启动还是常规启动 |
| 用户操作数据 | 点击启动图标、点击通知、点击快捷方式、被系统拉起 | 分析用户的启动入口偏好 |
| 性能指标数据 | Application.onCreate耗时、onCreate时间、首帧渲染时间、启动完成时间 | 量化启动速度,做性能优化 |
嗯,这里要特别注意系统环境数据。我在项目中遇到过一位同事,他把 CPU 核心数都埋进去了,实际上大多数设备都是 8 核,这个数据基本没用。建议只采集那些在性能问题定位中真正能用得上的,比如低内存状态、低存储状态这些。
3.2 用户行为 vs 系统状态
很多同学会把这两个概念搞混。举个例子:用户点击了启动图标,这叫用户行为;系统在 Application.onCreate 里做了初始化,这叫系统状态。两者要分开考虑,但又不能完全割裂。
你想想看,用户行为是“谁在什么情况下做了什么”,系统状态是“当前系统和应用处于什么水平”。我们埋点的目的,就是要把这两个维度对应起来。比如:
- 用户行为 + 系统状态 = 完整的启动场景
- 用户行为 + 性能指标 = 用户对启动速度的真实体验
- 系统状态 + 性能指标 = 技术优化方向
再补充一个容易踩坑的点:系统状态数据不要只采集一次,启动过程中不同阶段的状态可能不同。比如刚启动时内存可能很充足,但初始化了几个库之后就紧张了。我曾经因为只采集了启动开始时的内存,结果漏掉了某个第三方库加载时的内存峰值。
3.3 优先级排序:哪些数据必须采集
启动流程涉及十几个方法回调、几十个初始化步骤,不可能每个都埋点。我通常用“影响面 × 问题频率”这个矩阵来排序。
| 优先级 | 条件 | 示例 |
|---|---|---|
| P0(必须) | 影响整个启动时长,且经常出问题 | Application.onCreate总耗时、主线程耗时操作、崩溃点 |
| P1(重要) | 影响面大但频率低,或频率高但影响面小 | 某个核心库的初始化耗时、网络首次请求耗时 |
| P2(可选) | 影响面小且频率低 | 个别第三方SDK的版本号、A/B实验变量 |
排序时,我个人习惯先列出所有可能的埋点候选,然后问自己三个问题:
- 这个数据丢了,我能不能排查出启动慢的问题?—— 不能?那就是P0。
- 这个数据变化了,会不会直接影响用户感知?—— 会?那就是P1或以上。
- 如果只能保留10个埋点,我会保留哪10个?—— 这样一逼自己,很多无关的数据就自动过滤掉了。
3.4 如何确定启动阶段的行为边界
启动什么时候算开始?什么时候算结束?不同定义会导致采集的数据完全不一样。我见过有的团队把“用户看到主界面”当作启动完成,有的把“网络数据加载完毕”算完成。我建议用“用户可交互”作为标准,因为这是用户感知到的启动完成。
对应的,需要采集的数据也要围绕这个边界来设计:
- 开始点:Process.start() 或者 Application.attachBaseContext()?我个人习惯从 Application.onCreate() 开始,因为这是开发者可以控制的第一个点。
- 结束点:Activity.onResume() 之后,用户能看到界面并且能点击。
- 中间关键阶段:ContentProvider初始化、首帧绘制、数据预加载、网络请求等。每个阶段都需要有一个开始和结束的时间戳。
你可能会问:为什么强调时间戳?因为在分析时,你要知道时间消耗在哪个阶段。有了阶段时间轴,你才能精准定位瓶颈。后面章节我会具体讲怎么采集时间戳。
3.5 梳理知识结构图
下面这张图,把启动阶段埋点需求分析的核心逻辑串起来了。你可以把它当作脑子里的一张地图,后面写代码时随时对照。
3.6 避坑清单
最后列几个我踩过的坑,你可以直接拿去做 checklist:
- 别把操作系统调度行为当作应用行为。比如“冷启动时CPU频率变化”这个数据,它不是我们的 App 能控制的,埋了也没用。
- 注意隐私合规。用户行为数据不能包含个人身份信息,比如 Android ID、IMEI 这些,除非你有明确授权。我在某次合规审查中因为这个被怼过。
- 启动阶段埋点要轻量。不要在启动过程中做网络请求、写大文件,否则你埋的是启动性能本身。我一般用内存队列+异步写库的方式。
- 优先级不是一成不变的。新版本如果修改了某个初始化逻辑,对应的埋点优先级可能需要调整。记得在每次发版前重新 review 一遍埋点列表。