前言
APP打开的一瞬间速度快慢;就好比人的第一印象,快速的打开一个应用往往给人很舒服的体验。app经常性卡顿启动速度很慢,这无疑是对用户的流失。
启动方式介绍
APP启动的方式分为3种:冷启动、热启动、温启动。
- 冷启动:应用程序从头开始,须要作大量的工做,耗费的时间最多。
- 热启动:系统会把你的活动放在前台,活动有驻留在内存中,好比按了home键。相对于冷启动,开销较低。
- 温启动:用户退出应用程序,随后又从新启动,可是活动的进程是有驻留在后台的,好比按了back键退出应用。
启动过程
目前以app为例,介绍app的点击app icon到应用完全启动的过程。
1、用户在Launcher上点击App Icon
2、系统为App创建进程,显示启动窗口,创建应用进程信息
3、App在进程中创建自己的组件
- 初始化应用中的对象(比如 Application 中的工作);
- 启动主线程(UI 线程);
- 创建第一个 Activity或者Controller;
- 加载内容视图(Inflating);
- 计算视图在屏幕上的位置排版(Laying out);
- 绘制视图(draw);
只有当应用完成第一次绘制,系统当前展示的空白背景才会消失,才会被Activity的内容视图替换掉。也就是这个时候,用户才能和我们的应用开始交互。这个过程可以用下面这幅图来描述:
上述流程里面的红色框部分是由系统控制的,跟ROM相关的,我们无法处理。对于启动速度,我们能够控制的是Application的创建过程。
优化策略(以安卓app为例)
1 优化onCreate, onStart,onResume函数
(1) 由于许多内容在activity的UI初始化和生命周期中需要用到,所以大部分activity中的成员需要在onCreate中通过new的方式赋值。这就要求new的类的构造函数应该尽可能简单,不要有耗时操作,以便快速执行。
(2) 不要在这些函数中new暂时用不到的内容,比如一些提醒的dialog,可以在需要提醒的地方再去创建。
2 优化布局文件
(1) 减少UI的布局嵌套层数,从而减少layout时间。 简化XML布局,界面布局时,层次越多,加载的时间就越长。因此应该尽可能的减少布局层次。如果实在层次太多并且无法简化,建议不使用XML布局,直接在代码中进行布局 判断嵌套布局是否可以优化的方法: i. 借助工具Hierarchy Viewer,可以看到layout比较耗时的节点。 ii. 直接review xml布局文件。
(2) 尽量使用RelativeLayout替换LinearLayout。
(3) 尽量为所有分辨率创建资源,减少不必要的硬件缩放,这会降低UI的绘制速度。
(4) 首次不需要显示的节点,尽量设置为GONE。
3 优化draw过程
(1) 去掉不必要的背景,比如如果子节点和父节点size一样,那么父节点的background可以不设或者设为null.
(2) 尽可能少用或者不用高质量图片,以提高运行效率。
4 优化数据访问
有些属性需要在onCreate就获取,而这些属性保存在ContentProvider中。可以从下面两方面进行优化:
(1) 少用cursor.getColumnIndex。可以在建表的时候用static变量记住某列的index,直接调用相应index而不是每次查询。
(2) 查询时返回更少的结果集及更少的字段。只返回需要的字段和结果集,更多的结果集和字段会消耗更多的时间及内存。
5 优化自定义控件或UI部件
自定义控件和UI部件,不管这些控件是否支持xml化,实现它们的代码质量很重要,要尽可能简化它们的构造过程。
6 代码方面的优化
(1) 使用缓存。尽量将需要频繁访问或访问一次消耗较大的数据存储在缓存中。
(2) 使用多线程。比较耗时的过程,尽可能的使用异步加载。避免UI主线程阻塞,发生长时间不响应。
(3) 只需要获取图片的高宽时,可以设置InJustDecodeBounds为true。这样就不会去decode图片,减少了图片解析的时间。
(4) 判断语句如果较多时,尽量使用switch..case..,而不是使用if..else..。因为if..else..是从上到下进行判断,而switch..case..有对判断条件进行优化。
(5) for()循环中有if()判断,考虑实现为将if()判断语句放在for()语句外面,减少判断次数,for语句可以快速执行。
(6) String的拼接尽量使用io流。
(7) 数据类型和数据结构的选择。比如:hash系列数据结构查询速度更优,ArrayList存储有序元素。
7 其它
通过使用Show GPU Overdraw去检测Overdraw,最终可以通过移除不必要的背景以及使用canvas.clipRect(重复绘制覆盖区域)解决大多数问题。
8 减少App启动时的耗时操作
1、减少App启动时的初始化操作:App启动时,会进行一些初始化操作,比如加载资源、数据库连接等,如果这些操作花费的时间过长,就会导致App启动速度变慢。因此,应该尽量减少App启动时的初始化操作,可以采用懒加载的方式,将一些不是必要的初始化操作放到后面,而不是在App启动时就完成。
2、减少App启动时的网络请求:App启动时,如果要发起网络请求,会增加App启动时间,因此,应该尽量减少App启动时的网络请求,如果有必要发起网络请求,可以采用异步的方式,将网络请求放到后台,而不是在App启动时就发起网络请求。
9 缩短App启动时的加载时间
1、减少App启动时的资源加载:App启动时,会加载一些资源,比如图片、音频等,如果这些资源太多,就会增加App启动时间。因此,应该尽量减少App启动时的资源加载,可以采用缓存的方式,将一些常用的资源放到本地,而不是每次都要从网络上加载。
2、减少App启动时的代码加载:App启动时,会加载一些代码,如果这些代码太多,就会增加App启动时间。因此,应该尽量减少App启动时的代码加载,可以采用模块化的方式,将一些不常用的代码放到模块中,而不是每次都要加载。
10 优化App启动时的内存占用
1、减少App启动时的内存占用:App启动时,会占用一些内存,如果这些内存太多,就会增加App启动时间。因此,应该尽量减少App启动时的内存占用,可以采用内存优化的方式,将一些不常用的内存释放掉,而不是每次都要占用。
2、减少App启动时的线程数量:App启动时,会创建一些线程,如果这些线程太多,就会增加App启动时间。因此,应该尽量减少App启动时的线程数量,可以采用多线程优化的方式,将一些不常用的线程关闭,而不是每次都要创建。
总结
总结起来,APP启动速度优化就一句话:让系统在启动期间少做一些事。当然我们得先清楚工程里做的哪些事是在启动期间做的、对启动速度的影响有多大,然后case by case地分析工程代码,通过放到子线程、延迟加载、懒加载等方式让系统在启动期间更轻松些。
另外:
可以添加一个简单闪屏页面来过渡(视觉上会“快”些),避免首次加载展示过多的数据(如果这个就可以理解为app已启动。否则可在第一次展示的首页做更少的耗时任务,是用缓存,或者异步加载、懒加载的方式来展示非必需的大量数据内容)。
参考文章:Android性能优化——(APP启动速度优化)