热启动出现 500 ms 白屏,如何区分是 Activity 重建还是 WebView 初始化

解读

面试官把“500 ms 白屏”抛给你,核心想验证三件事:

  1. 能否把“现象”拆成“可量化指标”;
  2. 是否熟悉 Android 启动链路(Activity 生命周期、Window 渲染、WebView 冷/热启动差异);
  3. 能否用最小侵入、可落地的监控手段快速归因,而不是一上来就改代码、加日志。
    500 ms 在国内中端机上已接近用户可感知上限,必须区分是“Activity 本身创建慢”还是“WebView 拖了后腿”,才能决定是让客户端瘦身、还是让 Web 资源预加载、还是让 ROM 厂商开 WebView 多进程。

知识点

  1. Android 启动分类:冷启动(进程不在)/ 热启动(进程在,Activity 被回收或仅 stop)。
  2. Activity 重建触发点:后台被回收、旋转屏幕、暗黑模式切换、字体大小调整、系统回收优先级。
  3. WebView 首次初始化:在 Android 59 上首次 new WebView() 会同步加载 Chromium 主 so 与 pak 资源,耗时 80400 ms;10 以后多进程预加载,耗时下降 50% 左右。
  4. 白屏本质:DecorView 尚未完成第一次绘制(ViewRootImpl.performTraversals),窗口背景色默认白色。
  5. 国内主流监控工具:
    • 系统级:adb shell am start -W、systrace、perfetto;
    • 代码级:ActivityLifecycleCallbacks、Choreographer.FrameCallback、WebViewClient.onPageStarted;
    • 线上埋点:字节码插桩(ASM)、AspectJ、Matrix、Booster、Soloπ;
    • 厂商接口:HUAWEI HiTouch、OPPO Atlas、小米 MiPerf(需权限)。
  6. 关键指标:
    • Activity 级别:onCreate() 到 onWindowFocusChanged() 耗时;
    • 渲染级别:Choreographer 首帧时间戳 – startActivity 时间戳;
    • WebView 级别:new WebView() 到 onPageStarted() 耗时;
    • 系统级别:ReportFullyDrawn() 到 AMS 启动时间戳(adb -W 给出)。

答案

现场回答建议按“复现→采集→对比→验证”四步落地,既体现方法论,又给出可量化结论。

  1. 复现
    用 adb 命令保证热启动路径一致:
    adb shell am start -S -W -n pkg/.MainActivity # 先强停,测一次冷启动
    再按 Home 退后台,20 s 后再次 start(进程仍在),即热启动。
    连续 10 次,确认白屏稳定在 500 ms ±50 ms。

  2. 采集
    a) 系统侧:
    adb shell am start -W … 返回的 TotalTime 包含 AMS 到 Activity 首次 idle 的时间;
    同时开 systrace:
    python systrace.py -a pkg -b 32768 sched gfx view webview -o trace.html
    b) 代码侧:
    在 Application.attachBaseContext() 记录 startTs;
    在 Activity.onCreate() 记录 createTs;
    在 onWindowFocusChanged(true) 记录 focusTs;
    在 new WebView() 前后打 webviewCreateTs;
    在 WebViewClient.onPageStarted() 记录 pageStartTs。
    把以上 5 个时间戳随日志吐出。

  3. 对比
    取 10 组数据求平均:

    • Activity 创建耗时 = focusTs – createTs
    • WebView 初始化耗时 = pageStartTs – webviewCreateTs
    • 总白屏耗时 = focusTs – startTs
      若 Activity 创建耗时 ≈ 总白屏耗时,且 WebView 初始化耗时 < 50 ms,则瓶颈在 Activity 重建;
      若 WebView 初始化耗时 ≈ 400 ms,且与总白屏基本相等,则瓶颈在 WebView。
  4. 验证
    快速验证法:

    • 把 Activity 的 android:configChanges 加上 orientation|screenSize|uiMode,强制不重建,若白屏降到 100 ms 内,则确认是重建问题;
    • 或者在 Application 中提前 new WebView() 并缓存到静态变量,热启动时直接取用,若白屏降到 100 ms 内,则确认是 WebView 问题。
      线上灰度可用字节码插桩,把“首次 WebView 创建耗时”作为自定义性能指标上报,结合用户机型、ROM、WebView 版本做聚类,避免实验室偏差。

结论模板:
“通过 adb -W + systrace 定位,热启动 500 ms 白屏中 380 ms 消耗在首次 new WebView(),Activity 生命周期仅 80 ms,因此主要瓶颈是 WebView 初始化;已在 Application 中采用异步预加载方案,灰度后 90 分位白屏降至 160 ms。”

拓展思考

  1. WebView 预加载的“度”:
    国内厂商 ROM 对 WebView 多进程开关策略不一,预加载过早可能拖慢 Application 启动,反而拉长冷启动。可结合用户点击预测(序列模型)动态决定预加载时机。

  2. 白屏≠首帧:
    部分场景窗口背景已换成透明或品牌图,用户感知不到白屏,但首帧时间仍高。线上需同时监控“视觉首帧”(录屏 OCR 识别)与“技术首帧”(Choreographer),避免指标与体验错位。

  3. 低内存回收场景:
    国内后台保活限制严格,热启动往往伴随“进程存活但 Activity 被回收”,此时重建时间不仅取决于 XML inflate,还受内存压力影响。可结合 /proc/meminfo、ActivityManager.getProcessMemoryInfo() 把“可用内存”作为维度下钻,指导云端下发差异化预加载策略。