18. 启动闪屏优化:设置启动主题、使用SplashScreen API、减少白屏/黑屏时间
闪屏优化,说白了就是解决用户点击图标后那一段「干瞪眼」的时间。我见过太多App启动时先闪一下白屏,再跳转闪屏页,最后才进入主页——这种体验,用户没卸载真的是给面子了。
今天咱们就聊聊怎么把这段空白时间压到极致。我个人习惯把闪屏优化分成三个层次:视觉欺骗、系统API利用、冷启动加速。咱们一个一个来。
18.1 为什么会有白屏/黑屏?
先搞清楚根因。Android应用启动时,Zygote进程会fork一个新进程,然后加载Application、创建主线程、初始化Activity。这个过程需要时间。
但系统不会让用户干等着。它会先根据你的AndroidManifest.xml中设置的android:theme,绘制一个「预览窗口」(Preview Window)。如果你没设置主题,默认就是白色或黑色背景——这就是白屏/黑屏的由来。
核心结论:白屏/黑屏不是Bug,是系统在等你初始化完成。我们要做的,是让这个「等待画面」看起来不那么突兀。
18.2 设置启动主题:最简单的视觉欺骗
这是最基础、也最有效的方案。我早期做优化时,就靠这一招把启动感知时间缩短了40%。
思路很简单:给启动Activity设置一个自定义主题,背景用你的闪屏背景色或Logo,这样预览窗口看起来就像闪屏页本身。
步骤一:定义启动主题
<!-- res/values/themes.xml -->
<style name="Theme.Splash" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/splash_background</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowNoTitle">true</item>
</style>
步骤二:创建闪屏背景drawable
<!-- res/drawable/splash_background.xml -->
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/splash_bg_color" />
<item
android:gravity="center"
android:drawable="@drawable/ic_splash_logo" />
</layer-list>
步骤三:在Manifest中应用
<activity
android:name=".MainActivity"
android:theme="@style/Theme.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
步骤四:在Activity中恢复主题
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 在super.onCreate之前恢复正式主题
setTheme(R.style.Theme_App)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
我的经验:背景drawable不要用太复杂的矢量图,否则系统绘制预览窗口时反而会卡。我一般只用纯色+一个居中PNG Logo,文件控制在50KB以内。
18.3 使用SplashScreen API(Android 12+)
从Android 12开始,Google推出了官方的SplashScreen API。说实话,这玩意儿刚出来时我挺抵触的——又得适配新API。但用下来发现,它确实比我们自己手写的方案更优雅。
为什么推荐用官方API?
- 统一体验:所有App的闪屏动画风格一致,用户不会觉得跳戏
- 自动适配:系统会根据主题自动选择亮色/暗色模式
- 冷启动优化:API内部做了预加载优化,比我们自己写更高效
集成步骤
// 1. 在build.gradle中添加依赖
implementation 'androidx.core:core-splashscreen:1.0.1'
// 2. 在Activity中初始化
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 必须在super.onCreate之前调用
installSplashScreen()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
// 3. 在主题中配置闪屏样式
<style name="Theme.App" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_bg</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="postSplashScreenTheme">@style/Theme.App.Main</item>
</style>
注意:如果你要兼容Android 11及以下设备,还是得用18.2节的自定义主题方案。SplashScreen API只在Android 12+生效。我曾经在一个项目里只用了API,结果测试在Android 11上直接闪白屏——嗯,那次被测试小姐姐骂得不轻。
18.4 减少白屏/黑屏时间的进阶技巧
视觉欺骗只是治标,真正要减少等待时间,还得从冷启动链路下手。我总结了一套「三板斧」:
第一板斧:Application初始化懒加载
很多App在Application.onCreate里做了大量初始化——推送SDK、地图SDK、日志框架...这些完全可以延迟到真正需要时再加载。
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// 只初始化必须的
initCrashHandler()
initMemoryMonitor()
// 其他延迟初始化
InitManager.delayInit(this)
}
}
object InitManager {
private val initTasks = mutableListOf<() -> Unit>()
fun delayInit(context: Context) {
// 在闪屏页展示期间,利用IdleHandler执行
Looper.myQueue().addIdleHandler {
initTasks.forEach { it.invoke() }
false // 只执行一次
}
}
}
第二板斧:减少ContentProvider
每个ContentProvider都会增加启动时间。我见过一个App有8个ContentProvider,光初始化就花了200ms。能合并的尽量合并,能用懒加载的别用ContentProvider。
第三板斧:启动页数据预加载
闪屏页展示的这段时间,别让它闲着。我习惯在闪屏页的onCreate里启动一个异步任务,预加载主页需要的数据。
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
// 预加载主页数据
preloadHomeData()
// 延迟跳转
window.decorView.postDelayed({
startActivity(Intent(this, MainActivity::class.java))
finish()
}, 1500) // 至少展示1.5秒,避免闪一下就走
}
private fun preloadHomeData() {
lifecycleScope.launch(Dispatchers.IO) {
// 预加载网络数据、数据库查询等
HomeDataPreloader.preload()
}
}
}
18.5 知识体系总览
下面这张图是我自己整理的闪屏优化知识结构,你可以对照着检查自己的项目还有哪些没做到位:
18.6 避坑指南
做闪屏优化这些年,我踩过不少坑。挑几个典型的说说:
坑一:闪屏展示时间过短
我曾经把闪屏时间压到500ms,结果用户反馈「App闪了一下就没了,感觉像崩溃重启」。后来我改成至少1.5秒,用户满意度反而提升了。记住:闪屏不只是为了掩盖加载,更是品牌展示的机会。
坑二:背景Drawable太大
有次我放了一张高清PNG做闪屏背景,结果低端机上预览窗口绘制花了300ms——白屏时间反而更长了。后来换成纯色+小Logo,问题解决。
坑三:SplashScreen API和自定义主题混用
如果你同时设置了windowSplashScreenBackground和android:windowBackground,系统会优先使用API的配置。但低版本设备不认识API属性,就会回退到自定义主题。测试时一定要覆盖Android 11和Android 12两种场景。
18.7 性能指标参考
最后给出一组我常用的性能指标,你可以对照着优化自己的项目:
| 指标项 | 优秀 | 良好 | 需优化 |
|---|---|---|---|
| 白屏/黑屏持续时间 | 0ms(无感知) | < 200ms | > 500ms |
| 闪屏总展示时间 | 1.5s - 2.0s | 1.0s - 1.5s | < 1.0s 或 > 3.0s |
| Application.onCreate耗时 | < 100ms | 100ms - 300ms | > 500ms |
| 首帧绘制时间 | < 500ms | 500ms - 1s | > 1.5s |
嗯,闪屏优化做到这个程度,基本就到位了。记住一个原则:让用户感觉不到「等待」,而不是真的没有等待。视觉欺骗+性能优化双管齐下,才是最优解。
公众号:蓝海资料掘金营,微信deep3321