先上图。注意看底部,点击图标时会直接显示icon,然后在加载SplashActivity的View。使用的机型是oneplus 5t ,系统是android9.0。
首先要说明的是无论是APP启动,还是startActivity都是Activity的启动,最后都是ActivityManagerService启动一个新的Activity。咱们先看一下闪屏的原因。
闪屏的原因
当点击桌面的launch图标(桌面的launch也是一个app应用)时,如果这个Activity所属Application还没有在运行,系统会为这个Activity的先Fork出一个新进程(在Dalvik虚拟机中,每一个Application都是一个进程),但进程的创建与初始化都需要时间,在这个动作完成之前,如果初始化的时间过长,屏幕上可能没有任何动静,用户会以为没有点到按钮。
所以既不能停在原来的地方又没到显示新的界面,怎么办呢?这就有了StartingWindow(也称之为PreviewWindow)的出现,这样看起来就像Activity已经启动起来了,只是数据内容还没有初始化好。
StartingWindow一般出现在应用程序进程创建并初始化成功前,所以它是个临时窗口,对应的WindowType是TYPE_APPLICATION_STARTING。目的是告诉用户,系统已经接受到操作,正在响应,在程序初始化完成后实现目的UI,同时移除这个窗口。
这个StartingWindow就是我们要讨论的白屏和黑屏的“元凶”,一般情况下我们会对Application和Activity设置Theme,系统会根据设置的Theme初始化StartingWindow。Window布局的顶层是DecorView,StartingWindow显示一个空DecorView,但是会给这个DecorView应用这个Activity指定的Theme,如果这个Activity没有指定Theme就用Application的Theme。
黑屏和白屏
在Theme中可以指定窗口的背景,Activity的ICON,APP整体文字颜色等,如果说没有指定任何属性,就会用默认的属性,也就是上文中提到的空DecorView,所以我们的白屏和黑屏和空DecorView息息相关,我们给APP设置的Style就决定了是白屏还是黑屏。
如果选择了Black的系列的主题那么Activity跳转的时候就是黑屏:
@android:style/Theme.Black"
如果选择了Light的系列的主题那么Activity跳转的时候就是白屏:
@android:style/Theme.Light"
解决方案
1. 设置透明主题
从主题入手 ,先说一下demo中用到的App主题
<!-- Base application theme. -->
<style name="public_app_theme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/public_white</item>
<item name="colorPrimaryDark">@color/public_white</item>
<item name="colorAccent">@color/public_text_black_deep</item>
<item name="colorButtonNormal">@color/public_bg_button</item>
<item name="android:textColorPrimary">@color/public_text_black_deep</item>
<item name="colorControlHighlight">@color/public_bg_default_hint</item>
<item name="alertDialogTheme">@style/public_dialog_alert</item>
<item name="buttonStyle">@style/Widget.AppCompat.Button</item>
</style>
关于colorPrimary、colorPrimaryDark 等属性,这里就不做讲解了。
关于启动页 SplashActivity的主题,基于不同版本的SDK有两种设置。
在基础版本的 styles 中使用
<!-- 防止冷启动白屏-->
<style name="public_app_theme_noBar" parent="public_app_theme">
<!-- Customize your theme here. -->
<item name="android:windowBackground">@drawable/app_splash_bg</item>
<item name="android:windowFullscreen">true</item>
</style>
在v21版本(即android 5.0)中为了防止虚拟按键被占用,在 styles 中使用
<style name="public_app_theme_noBar" parent="public_app_theme">
<item name="android:windowBackground">@drawable/app_splash_bg</item>
<item name="android:windowFullscreen">true</item>
<!-- 防止虚拟按键被占用 -->
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
</style>
二者的资源地址如下图
2. 设置主题中的drawable
style中使用到的drawable也是两个文件
文件路径
drawable 路径下的 app_splash_bg.xml,第一个item是当前布局的背景,第二是需要显示的drawable以及显示位置。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 背景颜色 -->
<!--白色矩形 作为背景色-->
<item>
<shape android:shape="rectangle">
<solid android:color="@color/public_bg_default" />
</shape>
</item>
<!--单独的slogan图片 并且设置下间距-->
<item
android:bottom="@dimen/public_height_50dp">
<!--位置设置成靠下-->
<bitmap
android:gravity="bottom"
android:src="@drawable/app_ic_launcher" />
</item>
</layer-list>
drawable-v23文件下的app_splash_bg.xml,v23版本后可以设置layer-list中item的 width 和 height 属性。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 背景颜色 -->
<!--白色矩形 作为背景色-->
<item>
<shape android:shape="rectangle">
<solid android:color="@color/public_bg_default" />
</shape>
</item>
<!--单独的slogan图片 并且设置下间距-->
<item
android:width="@dimen/public_height_50dp"
android:height="@dimen/public_height_50dp"
android:bottom="@dimen/public_height_50dp"
android:gravity="bottom|center_horizontal">
<bitmap
android:gravity="fill_horizontal|fill_vertical"
android:src="@drawable/app_ic_launcher" />
</item>
</layer-list>
项目地址
目前项目是在我的开源组件化框架中插入的,没有进行筛选,所以可能会给大家查找带来不便,希望谅解。欢迎 star 我的开源 框架base,是基于 JessYan的开源框架mvpArms和ArmsComponent基础上二次开发的。
https://github.com/alinainai/Base/tree/master/app/src/main/res
OK,到此结束。