您所在的位置:主页 > 今视在线 > 资讯 > 正文

移动端启动速度!

2020-11-20 14:06:17 来源: 阅读:-

一款App,启动速度是最最大的门面,也是用户接触app的第一印象,试想,第一次进入app,就打不开,或者过了N秒才能进入主界面,会有多少用户有耐心继续使用下去。

所以这篇文章会从Android和iOS两个维度,根据启动机制的差异介绍一下启动速度的优化方式。



Android


启动分析

对于Android的启动分析,有一张很经典的图:

移动端启动速度

image.png

  • T0到T1:用户点击了图标,这时候首先响应操作的并不是app,而是rom的Launcher,然后就是大家熟知的AMS和WMS操作,这块讲起来有些复杂,之后会放到一个单独的文章中,而且这里的优化其实是app根本插不上手的,所以不是本文重点。在系统拉起进程之前,需要先显示一个预览窗口,这个是在app中配置的theme,如果theme是透明的,现在还是看到的桌面。这里不建议进行透明配置,会给用户一个点击延迟的错觉。iOS在这里处理的很好,虽然机制不同,但是在点击图标后,会先去显示Launcher画面,这个是一个固定配置,所以交互感觉更友好一些。
  • T1到T2:进程创建完毕了,就要走Application了,然后根据布局等等显示闪屏画面(如果有闪屏的情况)
  • T2到T3:闪屏结束了,开始显示首页了,但是实际上从Application(T1)开始,我们可能需要注册很多组件,或者加载很多三方库,这些都是较为耗时的
  • T3到T4:进入了首页,便是开始加载各类网络请求,以及对应的一些弹窗界面(业务需求)

优化方式

如果看懂了上述流程,我们可以理出一些优化点:

闪屏优化

如果禁用了预览窗口,那么用户到T2才能看到闪屏,之前都是桌面,这个体验是非常不好的,尤其是对于中低端机型,这时候可以加一个与闪屏界面相同的主题。

  1. 这块可以对比一下今日头条和小米有品(并无恶意,只是我的手机中这俩app是挨着的),点击今日头条,迅速显示闪屏,小米有品是先白屏在进入闪屏,虽然时间上差距可以忽略,但是对于中低端机型会非常明显(炫耀了一把我的高端手机)
  2. 另一种方式是,将闪屏和首页合成一个Activity,减少一个Activity的耗时,微信这样做后,据说减少了100ms,并未实操,感兴趣的朋友可以试一下。

三方库优化

上面提到了组件注入,以及三方库加载,这个是一个耗时很高的地方,也是一个最大的优化点,合理安排业务,将一些不是马上要用的三方库放到后面再去加载。或者使用懒加载的方式。

但是这里要特别注意一件事,之前遇到了一种情况,讲一个三方库变成了懒加载,但是由于使用的地方太多,一些case未回归,导致个别地方使用的时候未加载成功,所以功能失效了。使用这种方式一定要切记回归case

业务优化

优化业务,为什么说要优化业务呢,启动的每一毫秒都很重要,很多app一启动,会弹出N多弹窗,常见于各类电商软件,这些都是需要预加载的,都是需要时间的,所以这里需要合理衡量业务,砍掉无用的预加载,放到首页加载完成之后再去弹。

还有一些情况,如需要监听首次启动的各类广播,或者其他类型的监听器,当事件触发回调,可能出现大量代码并发。

当然还有其他类型的情况,都是业务太重导致的,这就需要梳理业务,让启动(重要的是首次启动)变得更清晰一些。

还有根据部分业务需求,可能出现在首页加载大的动画,这类需求,需要根据机型进行降级,低端机型低端处理,高端机型高端处理。

线程优化

线程优化包括两个方面,一是优化启动的线程数,这主要是减少CPU的压力。另一方面就是减少子线程和主线程交互时的一些block问题,比如虽然我们把耗时操作放到子线程了,但是主线程执行的一些任务可能等待子线程的锁(或者以回调形式执行),这就尴尬了,尽量避免这种逻辑发生。之前在iOS时发生过类似的事情,启动之后需要根据一个变量判断后续执行,但是这个变量是在子线程赋值的,有时候还会出现同时读写的问题。

GC优化

启动的过程中尽量避免大量的字符串操作,尤其是序列化,反序列化等等,防止出现较多的GC。这时候我们可以尽量复用一些对象,可以频繁赋值,但是不要频繁创建。

I/O优化

在负载过高的时候,I/O 性能下降得会比较快,一定要清楚启动的时候进行了哪些I/O操作,读了什么文件,进行了什么样的网络请求,请求回来什么样的内容,大小是多少等等。如果文件大小内容都是固定的还好,但是可能出现内容不定的情况。如果xx聊天工具,启动的时候需要加载聊天记录,这个文件可能很大,可能很小,需要根据不同情况进行处理。

数据重排

这个思路是之前在网上看到的,感觉很新颖,也记录下来了。这里要先介绍一下linux读取文件的机制。Linux读取文件会以block为单位,一次性在磁盘上读取4kb的内容,并且放到Page Cache中,这时候我们进行读取,实际不会发生真正的磁盘I/O。但是我们可能只有许多零碎的小文件,都是1K左右的,这时候我们可以考虑把数据进行重排,在同一时间需要用的数据放到一个文件中。只要4k以下,是可以一次读取的,不会浪费磁盘I/O的时间。

类重排

这也是一个新颖的概念,我们可以通过重写ClassLoader,看一下启动的过程中类的加载顺序,然后通过FaceBook提供的ReDex进行类重排,将启动过程中用的类往前排。

移动端启动速度

启动速度.png

iOS


启动分析

iOS的启动分析包含两个部分,一部分是pre-main,一部分是main,这个分类很好理解。

  • main()执行前:加载可执行文件(.o文件)加载动态链接库Objc 运行时的初始处理,包括 Objc 相关类的注册,category的注册,selector唯一性检查执行+load方法,attribute((constructor)) 修饰的函数的调用,C++静态全局变量
  • main()执行后,这个主要包括从main开始到appDelegatedidFinishLaunchingWithOptions中代码执行完毕。从这里开始都是我们自己的代码了,在这里一般是各类三方库的初始化,配置文件读写,首页加载等等。有的监测软件,也会将main执行后的代码以首屏开始加载为锚点,再进行分割,分成首屏渲染前和首屏渲染后。

优化方式

减少动态库的加载

pre-main中有个重要的步骤就是加载动态库,如果动态库过多,可以将动态库进行合并。非系统的动态库,可以支持合并成一个动态库。

减少类

减少加载启动后不需要的类,有时候业务冗余,或者代码年久失修,会有很多类其实不用了,但是仍然出现在工程中,再或者可能几个类能够合并成一个类。

+load优化

+load方法是在main函数之前调用的,遵从先父类后子类,先本类后列类别的顺序调用,+initialize方法是在main函数之后调用的,+initialize方法遵从懒加载方式,只有在类或它的子类收到第一条消息之前被调用的.+initialize只调用一次,init可多次调用。所以少在类的+load方法里做事情,尽量把这些事情推迟到+initiailize

控制C++全局变量个数

这主要是针对在函数外生命的变量,尽量减少这样的声明

业务优化(与android相似)

优化业务,为什么说要优化业务呢,启动的每一毫秒都很重要,很多app一启动,会弹出N多弹窗,常见于各类电商软件,这些都是需要预加载的,都是需要时间的,所以这里需要合理衡量业务,砍掉无用的预加载,放到首页加载完成之后再去弹。

还有一些情况,如需要监听首次启动的各类广播,或者其他类型的监听器,当事件触发回调,可能出现大量代码并发。

当然还有其他类型的情况,都是业务太重导致的,这就需要梳理业务,让启动(重要的是首次启动)变得更清晰一些。

还有根据部分业务需求,可能出现在首页加载大的动画,这类需求,需要根据机型进行降级,低端机型低端处理,高端机型高端处理。

线程优化(与android相似)

线程优化包括两个方面,一是优化启动的线程数,这主要是减少CPU的压力。另一方面就是减少子线程和主线程交互时的一些block问题,比如虽然我们把耗时操作放到子线程了,但是主线程执行的一些任务可能等待子线程的锁(或者以回调形式执行),这就尴尬了,尽量避免这种逻辑发生。之前在iOS时发生过类似的事情,启动之后需要根据一个变量判断后续执行,但是这个变量是在子线程赋值的,有时候还会出现同时读写的问题。

专注于首屏数据

之前的代码中,有这样的逻辑,在加载首屏的同时,还要加载第二屏的内容(TabBarViewController的第二个Tab),这个是没有必要的,如果需要预加载,可以将预加载放到首屏加载完成,可交互之后再去执行。

配置文件读取优化

只加载与首屏相关的内容,其他的配置内容可以放到首屏加载完成后去读取。

充分利用TimeProfiler

在进行首屏数据加载的时候,有很多方法可能造成耗时较长,之前遇到过一个这样的事情,首页加载时间较长,使用TimeProfiler看了一下时间,主要集中在首页图片加载中,首页有很多各式各样的图片,甚至于一些动画,这个时候就要看看耗时主要在哪,比如,UIImage存在延迟解压的问题。+imageNamed这个方法会在加载图片之后立刻进行解压,如果图片过大过大,这个在首屏展示的时候肯定会有性能影响,所以可以考虑使用imageWithContentsOfFile进行异步加载。当然还有其它方法的耗时,需要根据情况进行优化。

三方库优化

与Android类似,很多三方库不一定要在初始化的时候进行加载,需要梳理各类三方库的作用域,将不重要的三方库,放到首屏的viewDidAppear中去加载。这里看似简单,但是是需要认真梳理的,需要扣一下所有的三方库的应用场景,延迟加载会有什么样的影响。

移动端启动速度

iOS优化建议.png

总结

好了,大致就这些内容,里面很多方法,已经在实际工作中投入使用,还有一些,是对网上主流优化方法的整理,也打算进一步的试用,如果您有更好地方式,欢迎给我留言

推荐阅读:江西热线