onResume耗时操作也会影响白屏时间
如果在 Activity.onResume() 中执行了耗时逻辑,会直接影响“启动白屏”时间的持续,原因如下:
✅ 为什么 onResume() 中的耗时操作会影响启动白屏时间?
🔁 启动流程回顾关键点:
ActivityThread.handleResumeActivity()
→ performResumeActivity()
→ activity.performResume()
→ activity.onResume()
→ if (r.window == null) {
getDecorView(); // 创建 DecorView
wm.addView(decorView);
}
onResume() 是在 handleResumeActivity() 的中间阶段被同步执行的。此时:
• Window 已经准备好
• 但窗口还没真正完成绘制 / 首帧渲染
• 系统仍在等待 ViewRootImpl 执行 performTraversals() → draw(),来触发首帧完成。
📌 系统是如何判断“启动完成”的?
系统要等 首帧绘制完成,才会认为启动完成,即:
// ViewRootImpl.java
if (mReportNextDraw) {
performDraw();
mAttachInfo.mThreadedRenderer.draw()
surface.unlockCanvasAndPost()
session.finishDrawing(window) // 通知 WMS:我画完了
}
⚠️ 如果 onResume() 卡住(比如执行了阻塞 IO、大循环、或者主线程等待),就会阻塞 Choreographer 的 VSync 回调 → 延迟触发 performTraversals() → 首帧被推迟。
📉 这会带来的后果:
问题 | 说明 |
---|---|
⏳ 启动白屏延长 | 因为 DecorView 虽然已经加到窗口,但内容还未绘制出来,屏幕上是默认背景(白色或 launch theme) |
📱 用户感知卡顿 | 用户会看到停留在 splash / 启动页,像“卡住了一样” |
🧩 AppStartTrace 被记录 | Android Vitals / AppStart Tracing 会记录冷启动或热启动延迟 |
⛔️ reportFullyDrawn() 被延迟 | 如果你主动上报,也会晚 |
✅ 正确做法建议:
操作 | 建议 |
---|---|
⛔️ 避免 onResume() 执行耗时操作 | 包括网络请求、磁盘 IO、复杂计算 |
✅ 使用异步线程 | 将耗时逻辑放到 ViewModel、线程池、或者 Coroutine 等异步环境中 |
✅ 使用 SplashScreen#setKeepOnScreenCondition | 等异步加载结束后再移除 splash,防止白屏 |
✅ 参考代码优化示例(使用 Jetpack SplashScreen):
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition {
viewModel.isLoading.value // 加载完成前不移除
}
lifecycleScope.launch {
viewModel.loadInitialData()
}