Android应用启动白屏问题解决办法
白屏问题是应用启动过程中普遍存在的问题。
本文将介绍白屏问题的由来以及一种作者认为是市场上比较普遍的解决办法。
白屏问题的由来
我们已知当系统启动并启动App时需要消耗一定的时间,就算只有1s,也会让用户感觉有“延迟”现象。
我们在项目的MyApplication
中模拟一个1s的耗时
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Thread.sleep(1000)
}
}
来看效果
这是Google设计者为了让用户体会到点击图标后立马就有响应,而让App创建的过程中先展示一个空白窗口。
正是这个设计,我们在点击App应用图标之后,会看到一段时间的空白屏幕,这就是所谓的安卓应用启动白屏。
总结就是:
谷歌设计App启动的时候有一个预览的界面,在应用完成启动初始化之前都会显示这个预览界面,目的是为了让用户点击APP图标的时候有一个瞬间响应的交互体验。
而这个预览界面是由我们app应用主题android:theme
中的android:windowBackground
属性决定的,当我们不指定的时候android:windowBackground
的时候默认是一个近乎白色的颜色#fffafafa
。
来做一个代码跟踪
android:theme="@style/Theme.WhiteScreen"
查看应用主题---->
<style name="Theme.WhiteScreen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
...
</style>
查看父主题---->
<style name="Theme.MaterialComponents.DayNight.DarkActionBar" parent="Theme.MaterialComponents.Light.DarkActionBar"/>
一直跟踪到---->
<style name="Platform.AppCompat.Light" parent="android:Theme.Holo.Light">
...
<item name="android:windowBackground">@color/background_material_light</item>
</style>
---->
<color name="background_material_light">@color/material_grey_50</color>
---->
<color name="material_grey_50">#fffafafa</color>
我们看到android:windowBackground
属性最终在Platform.AppCompat.Light
主题中指定,而background_material_light
对应的颜色正是#fffafafa
。
所以默认情况下,我们点击应用图标,在应用完成启动初始化之前,看到的都是一个白色空白的屏幕。应用的启动时间越长,这个白屏的显示时间也就越长。
我们在MyApplication
中做一个耗时操作模拟应用启动初始化
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Thread.sleep(3000)
}
}
再来看效果,可以发现这时候白屏问题的解决就刻不容缓了。
解决方案
windowDisablePreview和windowIsTranslucent标签
谷歌虽然在主题中有提供如windowDisablePreview
和windowIsTranslucent
等标签,用来供用户设置不显示预览窗口 或 者将预览窗口设置为透明 这样两种功能,从视觉上让用户无法看出黑白屏,但实际上这两个标签更像是为了提供给开发者有这个选择权利而提供的标签,并不建议使用。
<!-- Base application theme. -->
<style name="Theme.WhiteScreen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
...
<!--设置系统的取消预览(空白窗口)为true -->
<item name="android:windowDisablePreview">true</item>
<!--设置背景为透明-->
<item name="android:windowIsTranslucent">true</item>
</style>
我们维持3s的延迟,然后将主题中的windowDisablePreview
或windowIsTranslucent
设置为true后查看效果
我们看到点击应用图标后,App会卡顿在那里,等待App启动加载完成后再显示第一个活动窗口。
这显然是和Google官方的设计理念背道而驰的。
正确的解决方法一定是顺着Google设计思想走,也就是让用户点击应用图标的时候有一个及时的响应交互。
改变android:windowBackground属性,替换默认空白预览页面。
当我们替换android:windowBackground
属性的值为我们应用自定义的页面。用户点击图标在等待应用初始化加载的过程中,看到的不再是一个空白页,而是一个与本应用相关的图片,这样就完美解决了应用创建过程中看到白屏的问题。其实这也正是市面上很普遍的解决方式。
在与Splash页面做衔接的时候我们有两种选择
1、预览页与Splash页面相同,Splash页面显示完成后直接跳到主页面。
2、预览页与Splash页面不同,先展示预览页,再展示Splash页面,最后再跳到主页面。
第一种,只要做到预览页和Splash页面显示效果完全相同,注意好适配即可,这里就不做详细描述了,感兴趣的朋友可以直接下载Demo查看,我们直接来看效果。
Splash的标题栏也懒得去了,大家明白意思就行。
我们主要看一下比较常见的第二种选择,因为在实际的业务需求中,我们可能会在Splash页面做一下页面定制,如插播广告等。这个时候就要求预览页与我们的闪屏页不同,如何做呢,也很简单。
1、自定义继承自AppTheme的主题
<!-1:自定义主题-->
<style name="LauncherTheme" parent="Theme.WhiteScreen">
<item name="android:windowBackground">@drawable/layout_launcher</item>
</style>
2、将启动Activity的theme设置为自定义的主题
<activity
android:name=".SplashActivity"
android:theme="@style/LauncherTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3、在启动Activity的onCreate
方法中,在super.onCreate
和setContentView
方法之前调用setTheme
方法,将主题设置为最初的AppTheme
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 注意这里将主题设置回应用的原有主题
setTheme(R.style.Theme_WhiteScreen)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
thread {
Thread.sleep(1000)
runOnUiThread(Runnable {startActivity(Intent(this, MainActivity::class.java))})
}
}
override fun onPause() {
super.onPause()
finish()
}
}
查看效果
这个效果图在Spash页会看到残影,这是录屏工具导致的,项目实际运行效果是看不到这个残影的。
值得一提的是,最后这两个效果,我们在MyApplication和SplashActivity中都是设置了延时的,现在你还能感觉到一丝丝的启动白屏吗?
文末有言
本篇文章的正文内容到这里就结束了。要知道的是我们做的仅仅是从视觉方面消除了白屏问题,并没有实际缩短应用的启动时间,想做出一个优秀的App,启动优化必须从有效缩短应用启动时间入手。
我们可以点开淘宝App看一下,粗略估计启动时间1s多。如果你觉得自己开发的应用没有淘宝那么复杂,启动时间达到了3s甚至4s,那就是时候考虑真正地在启动优化方面下点功夫了。
异步初始化,懒加载等都是我们值得借鉴和深入学习的技术。
文中Demo下载地址。
本系列文章引导页点击这里