探索App性能优化之绘制优化/UI流畅度优化
一、页面绘制对App性能的影响
绘制性能主要影响 :App的页面显示速度。
绘制影响性能的实质:页面的测量 & 绘制时间,一个页面通过递归完成测量 & 绘制过程
二、绘制优化思路和方向
思路:View的onDraw()要避免执行大量的操作
方向:降低View.onDraw()的复杂度 & 避免过度绘制(Overdraw)
三、绘制优化具体方案
(一) 降低View.onDraw()的复杂度
1、onDraw()中不要创建新的局部对象
因为onDraw())可能会被频繁调用,这样一瞬间产生大量的临时对象,不仅占用了过多的内存而且还导致系统更加频繁gc,降低了程序的执行效率。
2、onDraw()不要做耗时操作
不要执行成千上万的循环操作,尽管每次循环都是轻量级的,但是大量的循环仍然十分抢占CPU的时间片,这会造成view绘制不流畅出现UI卡顿现象(后面会针对UI卡顿做详细说明)。View的绘制帧率保证60fps,即每帧的绘制时间不超过16ms(16ms = 1000/60)。
(二) 避免过度绘制(Overdraw)
1、移除默认的Window背景background
- 问题描述:应用程序默认继承的主题windowBackground,如默认的Light主题。一般情况下,该默认的Window背景基本用不上,因为背景都自定义设置。若不移除,则导致所有界面都多1次绘制。
<style name="Theme.Light">
<item name="isLightTheme">true</item>
<item name="windowBackground">@drawable/screen_background_selector_light</item>
...
</style>
- 解决方案:移除默认的Window背景
方式1:在应用的主题中添加如下的一行属性 <item
方式1:在应用的主题中添加如下的一行属性
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 或者 -->
<item name="android:windowBackground">@null</item>
方式2:在BaseActivity的onCreate()中使用下面的代码移除
getWindow().setBackgroundDrawable(null);
<!-- 或者 -->
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
2、移除控件中不必要的背景
- 场景1:RecyclerView/ListView与item
列表页(RecyclerView/ListView)与其子控件(item)的背景相同都是白色,故可移除子控件(item)布局中的背景。
- 场景2:ViewPager与Fragment
1个ViewPager + 多个Fragment组成的首页界面,若每个Fragment都设有背景色,即ViewPager 则无必要设置,可移除。
3、减少布局文件的层级(嵌套)
- 使用布局标签
<merge/>
、<ViewStub/>
、<include/>
- 合适选择布局类型(LinearLayout/RelativeLayout)
四、UI流畅度优化
(一) UI卡顿原因
View的绘制帧数保持60fps是最佳,这要求每帧的绘制时间不超过16ms(1000/60),如果安卓不能在16ms内完成界面的渲染,那么就会出现卡顿现象。
(二) UI卡顿的原因分析
- 1、在UI线程中做轻微的耗时操作,导致UI线程卡顿
- 2、布局Layout过于复杂,无法在16ms内完成渲染
- 3、同一时间动画执行的次数过多,导致CPU和GPU负载过重
- 4、overDraw,导致像素在同一帧的时间内被绘制多次,使CPU和GPU负载过重
- 5、View频繁的触发measure、layout,导致measure、layout累计耗时过多和整个View频繁的重新渲染
- 6、频繁的触发GC操作导致线程暂停,会使得安卓系统在16ms内无法完成绘制
- 7、冗余资源及逻辑等导致加载和执行缓慢
- 8、ANR
(二) UI卡顿的优化
1、布局优化
- 用include、ViewStub、merge
- 不要出现过于嵌套和冗余的布局
- 使用自定义View取代复杂的View
2、ListView优化
- 复用convertView
- 滑动不加载
3、背景和图片优化
- 缩略图
- 图片压缩
4、避免ANR
- 不要在UI线程中做耗时操作