性能优化—启动优化

APP启动优化是app性能优化中的一种优化方式,也是整体项目优化所必须的一点。因为良好的应用启动速度可以带给用户更好的体验,增加留存率。

APP的启动方式

谷歌官方文档

应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动或热启动。在冷启动中,应用从头开始启动。在另外两种状态中,系统需要将后台运行的应用带入前台。建议您始终在假定冷启动的基础上进行优化。这样做也可以提升温启动和热启动的性能。

要优化应用以实现快速启动,了解系统和应用层面的情况以及它们在各个状态中的互动方式很有帮助。

冷启动

冷启动是指应用从头开始启动:系统进程在冷启动后才创建应用进程。发生冷启动的情况包括应用自设备启动后或系统终止应用后首次启动。这种启动给最大限度地减少启动时间带来了最大的挑战,因为系统和应用要做的工作比在另外两种启动状态中更多。

在冷启动开始时,系统有三个任务,它们是:

加载并启动应用。
在启动后立即显示应用的空白启动窗口。
创建应用进程。

系统一创建应用进程,应用进程就负责后续阶段:

创建应用对象。

启动主线程。

创建主 Activity。

扩充视图。

布局屏幕。

执行初始绘制。

一旦应用进程完成第一次绘制,系统进程就会换掉当前显示的后台窗口,替换为主 Activity。此时,用户可以开始使用应用。

启动优化iOS 启动优化程序是什么_加载


在创建应用和创建 Activity 的过程中可能会出现性能问题。

应用创建
当应用启动时,空白启动窗口将保留在屏幕上,直到系统首次完成应用绘制。完成后,系统进程会换掉应用的启动窗口,允许用户开始与应用互动。

如果您在自己的应用中使 Application.onCreate() 过载,系统将在应用对象上调用 onCreate() 方法。之后,应用生成主线程(也称为界面线程),并用其执行创建主 Activity 的任务。

从此时开始,系统级和应用级进程根据应用生命周期阶段继续运行。

Activity 创建
在应用进程创建 Activity 后,Activity 将执行以下操作:

初始化值。
调用构造函数。
根据 Activity 的当前生命周期状态,相应地调用回调方法,如 Activity.onCreate()。
通常,onCreate() 方法对加载时间的影响最大,因为它执行工作的开销最高:加载和膨胀视图,以及初始化运行 Activity 所需的对象。

热启动
应用的热启动比冷启动简单得多,开销也更低。在热启动中,系统的所有工作就是将您的 Activity 带到前台。只要应用的所有 Activity 仍驻留在内存中,应用就不必重复执行对象初始化、布局膨胀和呈现。

但是,如果一些内存为响应内存整理事件(如 onTrimMemory())而被完全清除,则需要为了响应热启动事件而重新创建相应的对象。

热启动显示的屏幕上行为和冷启动场景相同:在应用完成 Activity 呈现之前,系统进程将显示空白屏幕。

温启动
温启动包含了在冷启动期间发生的部分操作;同时,它的开销要比热启动高。有许多潜在状态可视为温启动。例如:

用户在退出应用后又重新启动应用。进程可能已继续运行,但应用必须通过调用 onCreate() 从头开始重新创建 Activity。
系统将您的应用从内存中逐出,然后用户又重新启动它。进程和 Activity 需要重启,但传递到 onCreate() 的已保存的实例 state bundle 对于完成此任务有一定助益。

查看APP启动耗时的方式

1、reportFullyDrawn()

调用Activity的reportFullyDrawn()。它将在log里报告从apk初始化(和前面Displayed的时间是一样的)到reportFullyDrawn() 方法被调用用了多长时间。

try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            reportFullyDrawn();
        }
    } catch (SecurityException e) {
    }

启动优化iOS 启动优化程序是什么_启动优化iOS_02

2.在应用启动的log中直接查看

必须要先停用过滤器,因为提供此日志的是系统服务器,不是应用本身。

启动优化iOS 启动优化程序是什么_加载_03

优化点

1、启动主题优化
为了解决启动页白屏问题,常用来透明主题来解决,但是会造成点击app图标有延迟启动感。

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowIsTranslucent">true</item>
</style>

所以有了更好的优化点,一般APP启动页都会配一张启动图,可以将theme的背景设置为启动图,

<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/splash</item>
</style>

在启动页设置一个新theme,这样会覆盖掉原来的theme,所以在setContentView之前要设置会原来的theme。。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setTheme(R.style.AppTheme)
    setContentView(R.layout.activity_main)

}

3.Application中优化

Application#attachBaseContext()

Application启动会经过attachBaseContext()–>onCreate();这时大家从attachBaseContext的生命周期联想到什么?没错就是MultiDex分包机制。想必大家都会发现,自从我们方法数超出了65535处理了分包之后,启动白屏/黑屏的问题就出现了,分包机制是导致冷启动缓慢的重要原因,而现在部分应用采用插件化的方式来避免MultiDex带来的白屏问题,这虽然是一种方法,但是开发成本实在高,对于不少应用来说是不必要的。

MultiDex可分成运行时和编译时两个部分:

编译期:将App中的class以某种策略拆分在多个dex中,为了减少第一个dex也就主dex中包含的class数;
运行期: App启动时,虚拟机只加载主dex中的class。app启动以后,使用Multidex.install,通过反射机制修改ClassLoader中的dexElements来加载其他dex;
从网上的多篇实践分析中,他们主要采用的是异步方式。因为App起始会先加载主dex包,那么我们可以自主去处理分包的工作,我们将启动页和首页需要的库、组件等主要class分在主dex中,从而达到精分主dex包的大小,具体的操作写法,大家可以参考网上MultiDex启动优化文章,但是大家要注意在主dex的分包过程中,主dex经过我们一系列的优化操作减少了主dex的大小,因此也增大了NoClassDefFoundError的异常的可能,此时会导致我们的应用启动失败的风险,所以在优化后我们一定做好测试工作。

Application#onCreate()

各种第三方工具初始化和业务逻辑初始化,影响启动时间。我们先对它们拆分成四部分。

  1. 必须在onCreate()且是主进程中初始化
  2. 可以延迟,但是需要在Application中初始化
  3. 可以延迟到启动页的生命周期回调中初始化
  4. 延迟到用的时候再初始化

可以根据自身项目先列出自己项目的每一个初始化,然后进行分类。

冷启动优化总结

对于冷启动优化,应该具体问题具体分析,像抠字眼的方式一样,一点点去扣,一点点把握细节