前言
在我们点击Android手机桌面APP图标时,有时候我么会发现,应用并不是直接进入闪屏页或者应用主页面,而是会有一个短暂时间的白屏才能进去。但如果我们点击Back键退出应用,在点击返回的时候却没有白屏或者白屏时间几乎不可见。为什么会出现这种情况呢?这就涉及到Android应用冷热启动的问题。
启动方式
Android应用的启动方式可以分为三种:冷启动,暖启动,热启动;不同的启动方式表示着应用加载的方式不同,相对应的就产生了应用UI呈现给用户所需要花费的时间不同。
启动时间
Android 4.4(API 19)开始,Logcat可以自动打印出应用的启动时间,这个时间值从应用启动(创建进程)开始计算,到完成是视图的而第一次绘制(第一个Activity的界面第一次对用户可见)为止。
Cold Start (冷启动)
什么是冷启动? 比如设备开机后应用第一次启动,系统杀死应用进程(包括:用户主动杀死进程和系统内存吃紧引发的Kill)再次启动等。
在Android系统中,APP启动时,系统为每个运行的应用至少分配一个进程(多线程应用申请多个进程)。从进程角度讲,应该冷启动的时候,是没有该应用的进程配置信息的(包括 Application ,四大组件等),这样冷启动是所做的工作就会比其他两种启动方式多。
冷启动时,系统主要任务有两件:
1,开始加载并启动APP;
2,创建应用进程信息,进入并显示第一个Activity UI。
而我们我看到的白屏就是在第二步,配置进程信息和第一个Activity UI渲染到页面之前所花费的时间。那么我们来分析一下系统创建应用进程后,所要处理的事情;
1,初始化应用中的对象(比如Application的创建及其onCreate中的工作)
2,启动主线程;
3,创建第一个Activity;
4,加载布局视图(Inflating);
5,初始化控件在屏幕上的位置(Laying out)
6,绘制视图(draw)
只有当应用完成第一次绘制,系统当前展现的空白背景才会被Activity的布局视图替换掉。这是用户才能应用进行交互。在这个流程中主要涉及到Application 的onCreate和第一个Activity的onCreate方法,它们均在View绘制展示之前进行处理。所以在应用自定义的Application类中和第一个Activity类中的onCreate方法处理的逻辑越多,冷启动花费的时间就越长。
Warm Start (暖启动)
当APP中的Activities被销毁,但在内存中常驻时,应用的启动方式就会变为暖启动。相比于冷启动,暖启动过程减少了对象的初始化,布局加载等工作,启动时间会缩短。但启动时,系统忍让会展现一个空白背景,直到第一个Activity的内容替换。
Lukewarm Start (热启动)
热启动产生的场景有很多,比如:用户点击Back键退出应用,然后马上就重新启动。这是布局依旧是之前绘制好的,所以花费的时间更少。
优化方案
应用的冷启动是无法避免的,也就是说冷启动时用户总需要经历一个等待启动时间。开发人员唯一能做的就是在 Application 和 第一个 Activity 中,减少 onCreate() 方法的工作量,从而缩短冷启动的时间。像应用中嵌入的一些第三方 SDK,都建议在 Application 中做一些初始化工作,开发人员不妨采取懒加载的形式移除这部分代码,而在真正需要用到第三方 SDK 时再进行初始化。
除此之外,还有一种方式就是通过设置应用主题背景的方法,把应用默认展现的白色背景替换被透明背景。我们新建一个主题样式:
<style name="LaunchStyle" parent="AppTheme">
<!--设置透明背景-->
<!--<item name="android:windowIsTranslucent">true</item>-->
<!--设置无标题-->
<!--<item name="android:windowNoTitle">true</item>-->
</style>
然后在AndroidManifast.xml文件中将主题设置给第一个启动的Activity
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:theme="@style/MyStyle">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
然后在修改MainActivity的onCreate中,在setContentView(R.layout.avtivity_main)加载布局之前把主题修改回来
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_main);
}
我们可以看到现在白屏是没有了,这是应为我们将应用主题背景设置为透明,在我们点击应用图标之后,其实就已经打开了应用,不过此时应用背景为透明,我们让看到的是桌面。虽然这样做白屏是没有了,但是我们可以明显看到应用打开呈现一种卡顿延迟的现象。这种效果相比于白屏更不可取(这是因为我在Aplication的onCreate方法中休眠了三秒)
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
除了上边这种方法,还有一种更好的解决思路。就是通过android:windowBackground" 设置自定义主题背景,这样就给到用户一种很好的视觉过渡效果。可以参考优酷APP效果,直接将原本展示白屏的页替换成应用的闪屏页。
<style name="LaunchStyle" parent="AppTheme">
<!--设置Appliction背景-->
<item name="android:windowBackground">@drawable/layout_launch</item>
</style>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<item android:drawable="@color/color_white" />
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/baidu" />
</item>
</layer-list>
这是最终的效果,当然如果添加些动画效果会更好。