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()
}

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