应用的启动分为冷启动、热启动、温启动; 而启动最慢、挑战最大的就是冷启动:系统和App本身都有更多的工作要从头开始!
- 冷启动
冷启动指的是应用程序从头开始:系统的进程没有,直到此开始,创建了应用程序的进程。 在应用程序自设备启动以来第一次启动或系统杀死应用程序等情况下会发生冷启动。 这种类型的启动在最小化启动时间方面是最大的挑战,因为系统和应用程序比其他启动状态具有更多的工作。 - 热启动
与冷启动相比,热启动应用程序要简单得多,开销更低。在热启动,系统会把你活动放到前台,如果所有应用程序的活动仍驻留在内存中,那么应用程序可以避免重复对象初始化,UI的布局和渲染。
热启动显示与冷启动场景相同的屏幕行为:系统进程显示空白屏幕,直到应用程序完成呈现活动。 - 温启动
用户退出您的应用,但随后重新启动。该过程可能已继续运行,但应用程序必须通过调用onCreate从头开始重新创建活动。系统从内存中驱逐您的应用程序,然后用户重新启动它。进程和Activity需要重新启动,但任务可以从保存的实例状态包传递到onCreate()中。
启动白屏
冷启动白屏持续时间可能会很长,这可是个槽糕的体验,它的启动速度是由于以下引起的:
- Application的onCreate流程,对于大型的APP来说,通常会在这里做大量的通用组件的初始化操作;
建议:很多第三方SDK都放在Application初始化,我们可以放到用到的地方才进行初始化操作。 - Activity的onCreate流程,特别是UI的布局与渲染操作,如果布局过于复杂很可能导致严重的启动性能问题;
建议
Activity仅初始化那些立即需要的对象,xml布局减少冗余或嵌套布局。
优化APP启动速度意义重大,启动时间过长,可能会使用户直接卸载APP。 启动速度优化方案
作为普通应用,App进程的创建等环节我们是无法主动控制的,可以优化的也就是Application、Activity创建以及回调等过程。
方案一
手动定制
关于启动加速方案,Google给出的建议是:
1.利用提前展示出来的Window,快速展示出来一个界面,给用户快速反馈的体验;
2.避免在启动时做密集沉重的初始化(Heavy app initialization);
3.定位问题:避免I/O操作、反序列化、网络操作、布局嵌套等。
官方文档给出的建议中,方向1属于治标不治本,只是表面上快;
方向2、3可以真实的加快启动速度。接下来我们就在项目中实际应用一下。
- 1.启动加速之主题切换
定义一个style:
<style name="AppTheme.Launcher">
<!--关闭启动窗口-->
<item name="android:windowDisablePreview">true</item>
</style>
<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(或者LoginActivity 、SplashActivity 反正就是启动后的首个Activity)恢复正常主题:
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把这个闪屏当做一个广告、品牌宣传的页面。
优化
来看看如何使用drawable方式实现的,修改之前的style:
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/branded_launch_screens</item>
</style>
drawable/branded_launch_screens
<?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”参数是为了防止在启动的时候出现背景的闪烁。
如果不用drawable的方式实现,直接将背景设置为一张图片也是可以的,更加简单:
<style name="AppTheme.Launcher">
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@mipmap/app_welcome</item>
</style>
最终:在启动的时候,会先展示一个界面,这个界面就是Manifest中设置的Style,等Activity加载完毕后,再去加载Activity的界面,而在Activity的界面中,我们将主题重新设置为正常的主题,从而产生一种快的感觉。不过如上文总结这种方式其实并没有真正的加速启动过程,而是通过交互体验来优化了展示的效果。
方案二
引用Jetpack 库 – SplashScreen
此处引用某公众号文章介绍:原文链接