很多App都会遇到以下几个常见的性能问题:
启动速度慢;界面跳转慢;事件响应慢;滑动和动画卡顿。
一、启动速度优化。
优化初始化任务:
1. 把一些初始化任务懒加载初始化
2. 把初始化任务并行化(异步化)
3. 使初始化任务可以插拔(一个任务出问题不会影响到其他的任务)
其他:
1. 控制线程数量,注意线程的使用,用自己的线程池替换三方或者二方SDK的线程池,线程太多占用cpu资源,
2. 使用缓存来减少I/O操作(读数据库,读文件,SharedPreference)减少网络请求(判断无网络直接返回)
3. 对于SharedPreference进行了专门的优化,减少单个文件的大小,将毫无联系的存储键值分开到不同文件中,
并且防止将大数据块存储到SharedPreference中,这样既不利于性能也不利于内存,
因为SharedPreference会有额外的一份缓存长期存在。
4. Activity使用热启动,在按Back键,不销毁activity,释放一些图片等占用内存大的资源
二、界面优化
布局复杂、过渡绘制多、Activity主要函数耗时、内容展示慢、界面重新布局(Layout)、GC次数
这些问题会导致界面卡顿。
1. 过度绘制
Activity使用默认主题背景,在layout中view尽量减少背景的设置(有前景内容,就不要设置和展示背景),
减少多层布局结构背景设置,减少Drawable的复杂Shape使用。
2. 优化布局层级
层级越多,测量和布局的时间就会相应增加,创建硬件列表的时间也会相应增加。
有时我们会嵌套很多布局来实现原本只要简单布局就可以实现的功能,有时还会添加一些测试阶段才会使用的布局。
通过删除无用的层级,使用Merge标签或者ViewStub标签来优化整个布局性能。比如一些显示错误界面、加载提示框界面等,
不是必须显示的这些布局可以使用ViewStub标签来提升性能。 另外要灵活使用布局,并不是层级越多就会性能越差,
有时候1层的RelativeLayout会比3层嵌套的LinearLayout实现的性能更糟糕。
除了灵活使用布局,另外我们还通过提前inflate以及在线程中做一些必要的inflate等来提前初始化布局,
减少实际显示时候的耗时。对于一些复杂的布局,做复用池,减少inflate带来的性能损耗,特别是在列表中。
3. 加快界面展示
1. 减少主线程的GC停顿,因为即使并行GC,也会对heap加锁,如果主线程请求分配内存的话,也会被挂起,
避免在onDraw中频繁分配较多和较大的对象,去掉ListView ,ScrollView等控件的EdgeEffect效果,来减少内存分配和加快控件的创建时间
2. 可以通过TraceView工具找出主线程的耗时操作以及操作次数和其他耗时的线程并作优化;
3. 对于网络请求,做好本地缓存,在网速慢或者无网络的时候展示,减少不必要的数据协议字段,减少名字长度等,并作压缩。
还可以通过分页加载数据来加快传输解析时间。因为JSON越大,传输和解析时间也会越久,引发的内存对象分配也会越多;
4. 注意线程的优先级,对于占用CPU较多时间的函数,也要判断线程的优先级。
5. 重写方法requestLayout、onSizeChanged,如果大小没有变化就阻断过多Layout请求。
4. 减少GC
1.减少对象分配,找出不必要的对象分配,如可以使用非包装类型的时候,使用了包装类型;字符串的+号和扩容;减少Handler.post(Runnable r)等频繁使用。
2. 对象的复用,对于频繁分配的对象需要使用复用池。
3. 尽早释放无用对象的引用,特别是大对象和集合对象,通过置为NULL,及时回收。
4. 防止泄露,除了最基本的文件、流、数据库、网络访问等都要记得关闭以及unRegister自己注册的一些事件外,还要尽量少的使用静态变量和单例。
5. 控制finalize方法的使用,在高频率函数中使用重写了finalize的类,会加重GC负担,使得性能上有几倍的差别。
6. 合理选择容器,在性能上优先考虑数组,即使我们现在习惯了使用容器,也要注意频繁使用容器在性能上的隐患点:首先是扩容开销, HashMap扩容时重新Hash的开销较大。其次是内存开销,HashMap需要额外的Map.Entry对象分配 ,需要额外内存,也容易产生更多的内存碎片。SparseArray和ArrayList等在内存方面更有优势。再次是遍历,对于实现了RandomAccess接口的容器如ArryList的遍历,不应该使用foreach循环。
5. 用性能分析工具采集数据,分析数据,找出性能优化点
通过Memory Monitor查看内存波动和GC情况,还可通过AlloCation Tracker工具观察内存的分配,发现很多小对象的分配问题。
利用Trace For OpenGL工具找出界面上导致硬件加速耗时的点,例如一些圆角图片的处理等。
使用TraceView分析方法耗时,开启GPU过度绘制监视以及GPU呈现模式使用Systrace分析界面渲染问题。
6. 编码时优化点
灵活使用final关键字,避免在循环中使用try catch,尽量少用Enum类型,可以使用临时变量代替this.member等
7. 测试启动时间方式
log方式在oncreate和onwindowFocus打点,记录Activity启动到界面展示的时间
可以使用hock方式记录启动时间,使用测试网站来测试,
android 5.0以上 使用adb shell am start -W 来测试时间。