Android APP启动优化

什么是APP启动屏幕

可能你也发现了,点击桌面图标,有时候出现一个白屏,然后才进入主界面,这是因为从桌面点击APP图标启动应用开始,程序会显示一个启动窗口等待Activity的创建加载完毕再进行显示。

来看一下Google官方文档《Launch-Time Performance》对应用启动方式的概述:

冷启动

冷启动指的是应用程序从头开始:系统的进程没有,直到此开始,创建了应用程序的进程。 在应用程序自设备启动以来第一次启动或系统杀死应用程序等情况下会发生冷启动。 这种类型的启动在最小化启动时间方面是最大的挑战,因为系统和应用程序比其他启动状态具有更多的工作。

热启动

与冷启动相比,热启动应用程序要简单得多,开销更低。在热启动,系统会把你活动放到前台,如果所有应用程序的活动仍驻留在内存中,那么应用程序可以避免重复对象初始化,UI的布局和渲染。
热启动显示与冷启动场景相同的屏幕行为:系统进程显示空白屏幕,直到应用程序完成呈现活动。

温启动

用户退出您的应用,但随后重新启动。该过程可能已继续运行,但应用程序必须通过调用onCreate()从头开始重新创建活动。系统从内存中驱逐您的应用程序,然后用户重新启动它。进程和Activity需要重新启动,但任务可以从保存的实例状态包传递到onCreate()中。

为什么出现白屏

冷启动白屏持续时间可能会很长,这可是个槽糕的体验,它的启动速度是由于以下引起的:
1、Application的onCreate流程,对于大型的APP来说,通常会在这里做大量的通用组件的初始化操作;
建议:很多第三方SDK都放在Application初始化,我们可以放到用到的地方才进行初始化操作。

2、Activity的onCreate流程,特别是UI的布局与渲染操作,如果布局过于复杂很可能导致严重的启动性能问题;
建议:Activity仅初始化那些立即需要的对象,xml布局减少冗余或嵌套布局。

优化APP启动速度意义重大,启动时间过长,可能会使用户直接卸载APP。

优化方案

优化方案主要是从主题切换的方向着手:

直接干掉

既然有这个Activity启动界面,那能不能直接不要这个呢,当然是可以:
定义一个style:

1
2
3
4
<style name="AppTheme.Launcher">
<!--关闭启动窗口-->
<item name="android:windowDisablePreview">true</item>
</style>

只需要再启动页面引用:

1
2
3
4
5
6
7
8
9
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.Launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

最后在MainActivity恢复正常主题:

1
2
3
4
5
6
7
8
9
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_main);
}
}

这样启动APP,就没有白屏,但会出现点击桌面图标而半天没有反应的现象,显然不好,很多APP把这个闪屏当做一个广告、品牌宣传的页面。

Material Design

其实Google针对APP闪屏,在Material Design规范launch-screens,也给出了非常详细的设计定义,有两种方案:

品牌展示

屏幕提供短暂的品牌曝光,来看看如何实现的,定义一个style:

1
2
3
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/branded_launch_screens</item>
</style>

drawable/branded_launch_screens

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<!--黑色背景颜色-->
<item android:drawable="@android:color/black" />
<!-- 产品logo-->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/empty_image01" />
</item>
<!-- 右上角的图标元素 -->
<item>
<bitmap
android:gravity="top|right"
android:src="@mipmap/github" />
</item>
<!--最下面的文字-->
<item android:bottom="50dp">
<bitmap
android:gravity="bottom"
android:src="@mipmap/ic_launcher" />
</item>
</layer-list>

其中android:opacity=”opaque”参数是为了防止在启动的时候出现背景的闪烁。关于layer-list介绍,见博客:用layer-list实现图片旋转叠加、错位叠加、阴影、按钮指示灯http://www.cnblogs.com/tianzhijiexian/p/3889770.html ,也同样只需要再启动页面引用和最后在MainActivity恢复正常主题。

或者

1
2
3
4
<style name="AppTheme.Launcher">
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@mipmap/app_welcome</item>
</style>

这里 windowBackground 直接用图片替换,更加简单。

主页预加载

使用与主界面UI一致的占位内容,给用户感觉已经在加载中了,这里模拟了一个高度为25dp的状态栏和一个高度为56dp的标题栏,定义一个style:

1
2
3
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/placeholder_ui</item>
</style>

drawable/placeholder_ui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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/colorPrimaryDark" />
<!--假装这里是个toolbar-->
<item
android:drawable="@color/colorPrimary"
android:top="25dp" />
<!--状态栏25+toolbar56=距离top81-->
<item
android:drawable="@android:color/white"
android:top="81dp" />
</layer-list>

源码

https://github.com/WuXiaolong/AndroidSamples

参考

官方文档Launch-Time Performance
https://developer.android.google.cn/topic/performance/launch-time.html

Android性能优化典范 - 第6季
http://hukai.me/android-performance-patterns-season-6/

Android 你应该知道的的应用冷启动过程分析和优化方案
http://yifeng.studio/2016/11/15/android-optimize-for-cold-start/



联系作者

我的微信公众号:吴小龙同学,欢迎关注交流,公号回复关键字「1024」有惊喜哦。