windowDisablePreview

介绍

android:windowDisablePreview=”true” 是 AndroidManifest.xml 中 <activity> 标签的一个属性,用于 关闭窗口预览图(即 StartingWindow)

背景介绍:StartingWindow 是什么?

当你启动一个新的 Activity 时,系统会立即为其创建一个 启动窗口(Starting Window),以防应用启动太慢时出现白屏。这个窗口通常显示的是:

• 应用图标 + 背景色(由启动主题提供)

• 或者整个 SplashScreen(API 31+)

这个窗口就是所谓的 “预览窗口”,它是由 WindowManagerService 通过 addStartingWindow() 添加的。

设置作用

<activity
    android:name=".MainActivity"
    android:windowDisablePreview="true" />

设置为 true 时表示:

• 禁用该 Activity 的预览窗口;

• 启动时 不会创建 StartingWindow,也不会自动显示主题背景。

使用场景

• 启动速度很快,不想看到中间过渡窗口;

• 自己实现了完整的 Splash 机制(如 SplashScreen API);

• 启动窗口样式不好看,或者和实际 UI 风格差异大;

• 希望自己手动控制窗口内容展示的时机(如游戏引擎、OpenGL 应用);

注意事项

1. 启用后,如果 onCreate() 中加载 UI 很慢,会直接看到白屏

2. 对于 API 31+ 使用 SplashScreen API 的项目,一般 不需要设置该标志,系统会自动处理;

3. 设置了 windowDisablePreview=true 之后,ActivityRecord#createStartingWindow() 会被短路跳过。

🔍 源码相关(简略)

// frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

boolean createStartingWindow(...) {
    if (mDisablePreviewScreenshots) {
        return false;
    }
    mWmService.mStartingSurfaceController.addStartingWindow(this);
    ...
}

mDisablePreviewScreenshots 来自 AndroidManifest 中的 windowDisablePreview 属性。

不能解决黑白屏问题

不能从根本上解决黑白屏问题,甚至可能带来副作用。

一、windowDisablePreview 是什么?

这是一个 Activity 的属性:

<activity
    android:name=".MainActivity"
    android:windowDisablePreview="true" />

当设置为 true 时,它的作用是:

阻止系统为该 Activity 显示启动预览窗口(Starting Window),也就是在 Activity 还未绘制完成时,系统不再自动创建一个背景窗口作为“过渡界面”。

二、黑白屏的产生原因?

黑白屏通常来自系统自动创建的 启动预览窗口(StartWindow):

• 如果 Activity 没有设置启动主题背景图(windowBackground),系统可能会默认显示 纯白纯黑

• 这通常发生在 setContentView() 之前,或 UI 未完成第一次绘制时。

三、设置 windowDisablePreview=”true” 会怎样?

优点:禁用了 StartWindow,避免了显示一个错误或未设定的纯色背景(如白屏或黑屏);

缺点:系统启动 Activity 时没有过渡界面,会出现“短暂的跳变”、“闪屏”或甚至更严重的启动卡顿体验;

并没有真正解决白屏/黑屏的根因 —— 因为根因在于你的 UI 没有及时绘制、启动主题设置不合理等。

四、更好的解决方案是?

1. 合理设置启动主题的 windowBackground

<style name="Theme.App.Launch" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="android:windowBackground">@drawable/splash_screen</item>
</style>

2. 使用 Android 12+ 官方的 SplashScreen API

val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { viewModel.isLoading }

3. 优化 Application 和 Activity 的启动耗时,避免在 onCreate() 执行阻塞操作。

总结

操作 效果 是否推荐
windowDisablePreview=true 禁用系统预览窗口,可能避免白/黑屏,但会造成“闪跳” ❌ 不推荐
合理配置启动 theme 的 windowBackground 显示品牌启动图或渐变背景,平滑过渡 ✅ 推荐
使用 SplashScreen API 官方方案,兼容性好,可控性强 ✅ 推荐
优化 onCreate 加载 减少启动时间,是根本手段 ✅ 强烈推荐

新老版本兼容

在不同 Android 版本中,android:windowDisablePreview=”true” 的行为确实存在差异,尤其是引入 SplashScreen API(Android 12 / API 31) 之后。下面是各版本兼容行为的详细说明:

1. Android 11 及以下(API ≤ 30)

• windowDisablePreview=”true” 完全关闭启动时的 StartingWindow(预览窗口);

• 效果是:启动过程中没有任何窗口展示,直到 Activity.setContentView() 渲染出实际 UI;

• 如果启动慢,会看到 明显的白屏

SplashActivity + Theme.Splash 是常见的替代方案。

2. Android 12 及以上(API ≥ 31)

从 Android 12 开始,引入了官方的 SplashScreen API,系统用 SplashScreenView 来替代传统 StartingWindow。

• windowDisablePreview=”true” 在这个版本仍然有效,但作用不同:

• 它会让系统 不插入系统级 SplashScreenView

• 不创建启动窗口 → 不会有 splash screen 动画,转场由 App 自己控制;

• 不再依赖 android:theme 中的 windowBackground 生成启动窗口;

• 一般不推荐禁用,除非你想自己全权控制启动效果(如游戏、特效 App)。

兼容性最佳实践

Android 版本 建议配置 原因与说明
API ≤ 30 使用 SplashActivity 或 Theme.Launcher,慎用 windowDisablePreview 否则可能白屏
API 31+ 使用官方 SplashScreen API,不要设置 windowDisablePreview=true 系统自动插入 Splash,表现更一致
混合支持 检查版本动态控制 Splash:if (Build.VERSION.SDK_INT >= 31) 对高版本用 API,自定义低版本兼容方案

🛠 示例兼容写法(Kotlin)

override fun onCreate(savedInstanceState: Bundle?) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        // 使用系统 SplashScreen API(API 31+)
        val splashScreen = installSplashScreen()
        splashScreen.setKeepOnScreenCondition { viewModel.isLoading }
    } else {
        // API 30及以下,使用 Theme + 自定义 Activity 实现 splash
        setTheme(R.style.AppTheme) // 恢复正式主题
    }

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}

小结

属性 API ≤ 30 API ≥ 31
windowDisablePreview 完全关闭 StartingWindow 禁用系统 SplashScreen
推荐做法 使用 SplashActivity 使用 SplashScreen API
是否可能白屏 否,系统已内建动画

在 Android 12 及以上(API ≥ 31)禁止SplashScreen

在 Android 12 及以上(API ≥ 31)中,可以通过设置 android:windowDisablePreview=”true” 来禁止系统自动插入的 SplashScreen(即 StartingWindow + SplashScreenView)

🔧 禁止系统 SplashScreen 的方法

在 AndroidManifest.xml 中为 MainActivity 设置:

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:theme="@style/Theme.App.Launch"
    android:windowDisablePreview="true">
</activity>

加上这一行:

android:windowDisablePreview="true"

就会让 ActivityRecord#createStartingWindow() 返回 false,从而不再添加 SplashScreenView。

效果验证(API 31+):

• 不再展示系统样式的启动窗口;

• SplashScreenView 不会插入;

• installSplashScreen() 虽然仍然可调用,但其返回值将 不生效(不会自动展示 Splash);

• 如果没有手动 setTheme 或立刻 setContentView,用户会看到黑屏或白屏

注意事项

1. android:windowDisablePreview=”true” 作用于 主启动 Activity

2. 该设置会完全禁止系统的 SplashScreen,包括主题窗口背景展示

3. 如果你自己没实现任何 Splash 机制,那么用户就会看到启动过程中的空白窗口。

推荐使用场景:

• 游戏或视频 App:使用 C++ 层 EGL/OpenGL 手动渲染首帧;

• 需要快速启动而 Splash 无意义的 App;

• 自定义复杂动画启动界面,不希望系统介入。

🔍 对应源码路径提示

// frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
boolean createStartingWindow(...) {
    if (mDisablePreviewScreenshots) {
        return false; // 不创建 SplashScreenView
    }
    ...
}

如果你想实现一个完全自定义的 Splash(比如自己绘制动画),可以在 Activity 内通过 Window.setBackgroundDrawable(null) 或 setTheme() 移除背景。

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