3. 启动窗口背景与主题切换优化

启动窗口背景与主题切换优化 学习卡片

为什么冷启动会先看到白屏或黑屏

Android 冷启动时,系统在应用进程尚未创建、Activity 尚未完成首帧绘制之前,会先显示一个「启动窗口」(Starting Window)。这个窗口的默认背景来自应用主题中的 windowBackground。如果主题是浅色,用户看到白屏;如果是深色,用户看到黑屏。它并不是应用真正绘制出来的界面,而是系统用主题背景临时填充的占位画面。

因此,消除白屏/黑屏的关键不是「加快首帧」,而是让这个占位窗口在视觉上与真实首屏一致,使启动过程看起来是「无缝」的。下面这张图展示了启动窗口背景从主题取值到用户感知的完整链路。

启动窗口背景取值链路与用户感知 应用主题 windowBackground windowIsTranslucent windowDisablePreview 系统启动窗口 进程未创建时显示 用主题背景填充 不执行应用代码 应用首帧 Activity 完成绘制 真实界面替换占位 用户看到真实内容 t=0 点击图标 进程创建中 首帧渲染完成 优化前:白屏/黑屏 windowBackground = 纯白/纯黑 与真实首屏差异大 用户感知:卡顿、闪屏 优化后:无缝过渡 windowBackground = 首屏同款背景 或使用 layer-list 渐变 用户感知:启动更快、更流畅 核心原则 启动窗口背景 ≠ 应用真实背景 → 用户看到「闪一下」 启动窗口背景 = 应用真实背景 → 用户感知「秒开」

配置启动窗口背景的两种方式

方式一:直接修改主题的 windowBackground,让它与首屏背景一致。这是最简单、最稳定的做法,适合首屏背景为纯色或简单渐变的场景。

<style name="AppTheme.Launch" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowBackground">@drawable/launch_bg</item>
    <item name="android:windowFullscreen">true</item>
</style>

其中 launch_bg 可以用 layer-list 定义,把品牌色、Logo 或渐变放在启动窗口上:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <gradient
                android:startColor="#1A73E8"
                android:endColor="#0D47A1"
                android:angle="270"/>
        </shape>
    </item>
    <item android:gravity="center">
        <bitmap android:src="@drawable/ic_launcher_foreground"
                android:gravity="center"/>
    </item>
</layer-list>

方式二:使用 windowDisablePreview 关闭预览窗口。这会让系统不显示启动窗口,但代价是用户点击图标后可能短暂无响应,体验反而更差,一般不推荐单独使用。

注意:不要为了「消除白屏」而把 windowBackground 设为透明或 null。透明背景会让桌面壁纸透出来,视觉上更混乱;设为 null 则可能触发系统默认黑屏。正确做法是让启动窗口背景与首屏背景一致。

验证窗口背景对感知启动速度的改善

验证方法不是看冷启动耗时是否下降,而是看「视觉连续性」是否改善。可以用高速相机或屏幕录制逐帧检查:从点击图标到首帧出现之间,是否存在与首屏明显不同的颜色块。

检查项 优化前 优化后 判断标准
启动窗口背景色 纯白 #FFFFFF 与首屏一致 #1A73E8 颜色差 ΔE < 3
首帧出现前画面 白屏持续 300~800ms 品牌色渐变 + Logo 无突兀色块切换
用户主观评分 「卡了一下」 「挺快的」 主观评分提升 ≥ 1 分
冷启动耗时 1200ms 1200ms(不变) 耗时不是本优化目标

关键认知:启动窗口背景优化不改变真实启动耗时,它改变的是用户对耗时的「感知」。当占位画面与真实首屏视觉一致时,用户会把整个启动过程感知为一个连续的品牌展示,而不是「白屏 + 突然出现内容」的割裂体验。

实操:为现有应用配置启动窗口背景

  1. 在 res/drawable/ 下新建 launch_bg.xml,用 layer-list 定义与首屏一致的背景(纯色、渐变或带 Logo)。
  2. 在 res/values/themes.xml 中新建 AppTheme.Launch,设置 android:windowBackground 指向 @drawable/launch_bg。
  3. 在 AndroidManifest.xml 中把启动 Activity 的 android:theme 设为 @style/AppTheme.Launch。
  4. 在启动 Activity 的 onCreate() 中,首帧绘制完成后调用 setTheme(R.style.AppTheme) 切回正常主题,避免启动主题影响后续界面。
  5. 用屏幕录制逐帧检查:点击图标后第一帧是否已经是品牌色背景,而不是白色或黑色。
// 启动 Activity 中切回正常主题
@Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.AppTheme); // 必须在 super.onCreate 之前
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

完成上述配置后,冷启动过程中用户看到的第一帧就是品牌色背景,首帧渲染完成后自然过渡到真实界面,白屏或黑屏现象消失。此时再用高速相机验证,应观察到从点击到首帧之间没有与首屏明显不同的颜色块。