相信大家都会有这样的经历,就是新创建的项目运行app后,发现会出现短时间的白屏或黑屏,然后才进入主界面。为什么会出现这样的现象呢?谷歌工程师出于怎样的考虑呢?我们该如何解决呢?基于这样几个问题,开始分析。
一、手机启动流程
当我们点击开机的时候,首先会通过引导芯片启动Linux内核,通过它会创建init进程,然后孵化出Zygote进程。然后Zygote进程孵化出SystemServer进程,初始化JVM虚拟机。然后初始化AMS\PMS等系统服务,最后才看到桌面的Launcher界面。具体得内部实现原理这里不做分析,大家只需要大致了解流程即可。
二、app启动方式
1、冷启动
程序重新开始,系统没有为该app创建进程。一般是在app第一次启动或者应用程序被系统完全清理。
1、热启动
程序依然存在内存中,只是从前台到后台。使用热启动不会走onCreate()方法,所以能够避免重复的布局的加载和渲染。需要注意的是如果程序被系统清理了,使用暖启动需要重新初始化一些对象,防止空指针的出现。
1、暖启动
它包含冷启动和热启动一些列的操作子集,比热启动消耗稍微多一点,它与热启动最大的区别是它必须调用onCreate()方法重新初始化操作,也可以从onCreate()方法保存的实例来获取某些对象的恢复。比如onCreate()方法参数中的Bundle对象,就可以存储一些对象。
三、冷启动流程
- 加载并启动app
- 为app创建一个空白的窗口
- 创建app进程
- 创建主activity
- 加载布局、绘制
由于在启动的过程中需要一系列的耗时操作,所以在冷启动的过程中会为app添加一个空白的窗口,防止用户感觉到明显的卡顿。这也是出现黑白屏的原因,黑白屏的颜色是根据Theme的颜色来定的。
四、黑白屏解决方案
1、方案1
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!--取消预览-->
<item name="android:windowDisablePreview">true</item>
<!--背景设置为透明-->
<item name="android:windowIsTranslucent">true</item>
</style>
可以取消预览也可以设置窗体为透明。这两种方式都是一样的效果。但是有一个缺点,就是当用户点击app图标的时候需要等待一会,才能进入主界面,体验不好,不推荐这种做法。
2、方案2
(1)在drawable下创建一个layer-list,代码如下:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The background color, preferably the same as your normal theme -->
<item android:drawable="@android:color/holo_green_light"/>
<item android:top="150dp">
<bitmap android:gravity="top"
android:src="@mipmap/pay_cloud" />
</item>
</layer-list>
第一个item设置纯色背景,第二个item设置一个图标,距离顶部150dp。
(2)在styles.xml下创建一个Theme,代码如下:
<style name="AppTheme.LaunchTheme">
<item name="android:windowBackground">@drawable/launch_layout</item>
<item name="android:windowFullscreen">true</item>
<item name="windowNoTitle">true</item>
</style>
windowBackground设置为我们自己的layer-list。并且设置为全屏显示。
(3)在AndroidMainifet.xml为我们的启动页设置Theme
<activity android:name=".SplashActivity" android:theme="@style/AppTheme.LaunchTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
为什么对activity设置该theme,为了不影响其他的activity,可扩展性好。
(4)启动页面布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SplashActivity">
<ImageView
android:id="@+id/go"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pay_alipay"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"/>
</RelativeLayout>
只在底部添加了一张图片。
五、运行效果
优化前:
优化后:
注意:一般闪屏页需要设计成纯色背景。如果使用一张图片,就会增大内存占用。所以说,最好的设计就是跟着系统走。