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() 移除背景。