App启动优化
Android Activity启动黑/白屏原因与解决方式
我们新建一个HelloWorld项目,运行在手机上时,Activity打开之前会有一个动画,而这个动画里是全白或者全黑的(取决于你的主题是亮还是暗),我们结束进程并点击在桌面上的APP图标,同样会有这个现象出现。当我们打开手机上安装的各个公司的APP时,可以发现其中大部分APP的启动动画都是有颜色有图案的,当然也有一小部分APP是全黑或全白的。那么为什么会出现这种情况呢?
Activity启动黑/白屏的原因
一个Activity的显示内容有哪些呢?我们在Activity的onCreate()方法中调用了setContentView()方法,传入了我们绘制的layout文件,也就是我们理论上应该看到的Activity内容。但是Android系统在启动一个新的Activity时,首先进行的并不是绘制Activity Content View,我们来看看一个Activity的UI结构。

我们可以看到,一个Activity中在ContentView的外围还有PhoneWindow、DecorView、TitleView,当Activity进行绘制时会先绘制这三个控件,这时ContentView还没加载进来,所以什么东西都看不到,系统会将屏幕填充主题默认的背景色,亮系主题填充白色,暗系主题填充黑色,就出现了Activity启动之前的黑/白屏现象。
解决办法
刚才说了,系统会为屏幕填充主题默认的背景色,那么要解决这个问题就应该从屏幕的背景下手了。一想到背景,第一反应就是去layout里设置ContentView的background,但是系统并不会先加载ContentView,那有什么在系统绘制之前就能调整屏幕背景呢?注意,系统会填充主题默认的背景色,所以主题会在绘制之前加载,我们可以修改主题的背景达到目的。一般一个APP第一个启动的Activity都是Splash,作为一个Splash并不需要标题栏,而且普遍是全屏的。那么我们可以将主题进行修改一下:
- 将主题背景变成透明的,这样在ContentView加载出来之前,我们会透过启动的Activity看到桌面,就不会有黑/白屏的现象。再把标题栏去掉,把Activity设置成全屏的,效果挺不错,缺点是如果启动的是一个有复杂耗时操作的Activity,那么会有一种延迟的感觉。
<!--启动透明样式-->
<style name="AppStartLoadTranslucent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:WindowFullscreen">true</item>
</style>
- 将主题背景设置成一张图片,但是图片的屏幕适配问题就需要考虑了,主题里的背景图片会自动拉伸。
<!--设置启动背景 splash页面设置个广告页-->
<style name="AppStartLoadBg" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@drawable/start_app_bg</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
<!-- manifest中设置splash主题 -->
<activity
android:name=".ui.SplashActivity"
android:screenOrientation="fullSensor"
android:theme="@style/AppStartLoadBg">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
现在一般主流都使用的第二种方式。
黑白屏
Android App 启动时出现的黑白屏(或白屏 / 黑屏) 是常见的用户体验问题,本质是启动过程中系统加载页面的延迟导致的短暂空白或默认背景显示。以下从成因、解决方案、最佳实践三个方面详细解析:
黑白屏的成因
当用户点击 App 图标时,系统会经历以下流程:
- 启动 App 进程(首次启动时)。
- 加载 Application 类(初始化全局资源、第三方库等)。
- 加载并初始化 Launcher Activity( setContentView 前的逻辑)。
- 绘制 Activity 界面(onCreate → onResume 后才开始绘制)。
在步骤 2~4 完成前,系统会先显示一个临时窗口(Preview Window) 作为过渡。这个窗口的背景由主题中的 windowBackground 决定:
- 若主题默认背景为白色(如
Theme.Light),则显示白屏。 - 若主题默认背景为黑色(如
Theme.Dark),则显示黑屏。 - 若自定义了
windowBackground,则显示对应颜色 / 图片。
核心原因:App 启动耗时过长(如 Application 初始化逻辑复杂、Activity onCreate 做了耗时操作),导致临时窗口显示时间超过用户可接受的阈值(通常 200ms 以上),被用户感知为 “黑白屏”。
解决方案(从根本消除或优化)
1. 优化启动速度(治本)
减少启动阶段的耗时操作,从源头缩短临时窗口的显示时间:
Application 优化:
避免在
onCreate()中执行耗时操作(如网络请求、大量计算、复杂初始化)。延迟初始化非必要的第三方库(如统计、监控 SDK),使用异步初始化(Thread 或 Coroutine)。
示例:
@Override public void onCreate() { super.onCreate(); // 必要的初始化(同步) initEssentialSDK(); // 非必要初始化(异步) new Thread(() -> initNonEssentialSDK()).start(); }
Activity 优化:
避免在
onCreate()、onStart()、onResume()中做耗时操作(如加载大量数据、初始化视图)。视图初始化延迟到
onWindowFocusChanged()或使用ViewTreeObserver监听布局完成后执行。示例:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 延迟初始化非首屏视图 getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(() -> { initNonCriticalViews(); // 布局完成后再初始化 }); }
2. 自定义启动过渡界面(治标,优化体验)
若启动速度无法进一步优化,可通过自定义临时窗口的背景,将 “黑白屏” 替换为启动页(Splash)风格的画面,让用户感知为 “有意设计的启动过程” 而非卡顿。
步骤如下:
Step 1:创建启动主题
在
res/values/styles.xml中定义一个专门用于 Launcher Activity 的主题,指定windowBackground为启动页图片或背景色:<!-- 启动主题 --> <style name="AppTheme.Launcher"> <item name="windowNoTitle">true</item> <item name="windowActionBar">false</item> <!-- 自定义背景:可放启动页图片(建议用.9图适配)或纯色 --> <item name="android:windowBackground">@drawable/splash_bg</item> <!-- 可选:隐藏状态栏/导航栏(全屏启动页) --> <item name="android:windowFullscreen">true</item> </style>splash_bg.xml(放在res/drawable下,可包含图片和背景色):<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 背景色 --> <item android:drawable="@color/white" /> <!-- 居中的Logo图片 --> <item> <bitmap android:gravity="center" android:src="@mipmap/ic_launcher" /> </item> </layer-list>Step 2:为 Launcher Activity 应用主题
在
AndroidManifest.xml中,为入口 Activity 配置上述主题:<activity android:name=".MainActivity" android:theme="@style/AppTheme.Launcher"> <!-- 仅启动时用这个主题 --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>Step 3:恢复默认主题
在 Activity 的
onCreate()中,在setContentView()前切换回 App 默认主题,避免后续页面受启动主题影响:@Override protected void onCreate(Bundle savedInstanceState) { // 切换回默认主题 setTheme(R.style.AppTheme); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }
3. 禁用预览窗口(不推荐)
通过主题设置 windowDisablePreview 可禁用临时窗口,但会导致点击图标后无任何响应直到页面绘制完成,用户可能误以为 App 未启动,体验更差:
<style name="AppTheme.NoPreview">
<item name="android:windowDisablePreview">true</item>
</style>
不推荐:仅适合启动速度极快(<100ms)的 App。
最佳实践
- 优先优化启动速度:通过启动器(如 Android Studio 的
App Startup)分析启动耗时,移除冗余初始化逻辑。 - 自定义过渡背景:将临时窗口背景设计为与启动页一致的样式(如 Logo + 背景色),让用户感知连贯。
- 避免过度设计启动页:启动页应简洁,且显示时间不宜过长(建议 ❤️ 秒),可在启动页中完成必要的初始化后立即跳转。
- 适配深色模式:若 App 支持深色模式,需为启动主题配置深色背景(如
values-night/styles.xml),避免夜间模式下出现刺眼的白屏。
总结
黑白屏问题的本质是启动延迟导致的临时窗口暴露,解决方案需结合 “优化启动速度” 和 “美化过渡界面”:前者从根本减少延迟,后者通过设计让用户感知更自然。实际开发中,推荐优先优化启动性能,再配合自定义主题实现平滑的启动体验。