启动速度优化实战
场景
用户反馈 App 冷启动耗时 3 秒以上,产品要求优化到 1.5 秒以内。
排查与方案
1. 测量基线
# 使用 adb 测量冷启动到第一帧的时间
adb shell am start-activity -W com.example/.MainActivity
# 关注 TotalTime(总耗时)和 WaitTime(等待完成时间)
在代码中精确埋点:
// Application.attachBaseContext → 第一个 Activity 首帧渲染
class App : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
StartupTracer.markStart()
}
}
class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
window.decorView.post {
StartupTracer.markFirstFrame() // 首帧上屏
}
}
}
2. 定位瓶颈
使用 App Startup Profiler(Android Studio → Profiler → Startup)或 Systrace 分析:
| 常见瓶颈 | 排查方法 |
|---|---|
| 主线程 I/O | Systrace 看 I/O wait |
| 大量 ContentProvider | 检查 Manifest 注册数量 |
| 重量级 SDK 初始化 | 在 Application.onCreate 中逐个计时 |
| 布局层级过深 | Layout Inspector 分析首页布局 |
3. 优化方案
| 方案 | 说明 | 效果 |
|---|---|---|
| 延迟初始化 | 非关键 SDK 移到首页渲染后 | ⭐⭐⭐ |
| 异步初始化 | CPU 密集型任务用协程并行 | ⭐⭐⭐ |
| App Startup 库 | 合并 ContentProvider,统一初始化 | ⭐⭐ |
| 闪屏页优化 | windowBackground 设置品牌图,消除白屏 | ⭐ |
| 布局优化 | ViewStub 延迟加载非首屏内容 | ⭐⭐ |
| 类预加载 | 异步线程提前触发关键类的类加载 | ⭐ |
// 使用 Jetpack App Startup 替代多个 ContentProvider
class AnalyticsInitializer : Initializer<Analytics> {
override fun create(context: Context): Analytics {
return Analytics.init(context)
}
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
准则
优化启动的核心思路:能不做的就不做,必须做的就并行做,不着急的就延后做。
面试答题要点
- 先说测量方法(adb、Profiler、埋点),体现数据驱动
- 再说排查思路(Systrace 看主线程阻塞)
- 最后说具体优化手段(延迟 / 异步 / 合并)
- 给出优化前后的数据对比