布局
对用户体验影响
良好的布局 可以减少系统渲染过程中对cpu的需求,从而提高桢率 提高用户体验。
原理
为什么要在16ms 完成消息处理
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。
用户容易在UI执行动画或者滑动ListView的时候感知到卡顿不流畅,是因为这里的操作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原 因可以导致丢帧,也许是因为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的绘制单元,还有可能是因为动画执行 的次数过多。这些都会导致CPU或者GPU负载过重。
什么叫过渡渲染
Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。
view tree的绘制过程
* View本身大小多少,这由onMeasure()决定,在viewtree 上递归调用该函数来计算每个view大小。
* View在ViewGroup中的位置如何,这由onLayout()决定,在viewtree 上递归调用该函数来计算每个view在父view中的位置。
* 绘制View,onDraw()定义了如何绘制这个View。在viewtree 上递归调用该函数来绘制每个view。
显然view tree 层级越深,过程越长,越可能产生卡顿
工具
Show GPU Overdraw 过渡渲染检测工具
我们可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,可以观察UI上的Overdraw情况。蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况,颜色越深 过渡渲染越厉害。我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。
HierarchyViewer
不合理的布局会使我们的应用程序UI性能变慢,HierarchyViewer能够可视化的角度直观地获得UI布局设计结构和各种属性的信息,帮助我们优化布局设计。HierarchyViewer是我们优化程序的工具之一,它是Android自带的非常有用的工具,可以帮助我们更好地检视和设计用户界面(UI),绝对是UI检视的利器
lint
冗余资源及逻辑等也可能会导致加载和执行缓慢,所以我们就来看看Lint这个工具是如何发现优化这些问题的.在Android Studio 1.4版本中使用Lint最简单的办法就是将鼠标放在代码区点击右键->Analyze->Inspect Code–>界面选择你要检测的模块->点击确认开始检测
优化点
功能越复杂,也越容易产生性能问题,所以常遇到布局复杂、过渡绘制多、Activity主要函数耗时、内容展示慢、界面重新布局(Layout)、GC次数多等问题
viewstub
iewstub标签同include标签一样可以用来引入一个外部布局,不同的是,viewstub引入的布局默认不会扩张,即既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。
viewstub常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度布局、网络失败显示的刷新布局、信息出错出现的提示布局等。
merge
在使用了include后可能导致布局嵌套过多,多余不必要的layout节点,从而导致解析变慢,不必要的节点和嵌套可通过hierarchy viewer(下面布局调优工具中有具体介绍)或设置->开发者选项->显示布局边界查看。
减少layout层级
(1) 首次不需要使用的节点设置为GONE或使用viewstub
(2) 使用RelativeLayout代替LinearLayout。(这里存在疑问,有时候1层的RelativeLayout会比3层嵌套的LinearLayout实现的性能更糟糕。)
使用OpenGL绘图
Android支持使用OpenGL API的高性能绘图,这是Android可用的最高级的绘图机制,在游戏类对性能要求较高的应用中得到广泛使用
防止overdraw
Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。
Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面 的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加 蓝色区域的占比。这一措施能够显著提升程序性能。
该优化并不复杂,通过去掉层叠布局中多余的背景设置、图片控件有前景内容的时候不显示背景、界面背景定义到Activity的主题中、减少Drawable的复杂Shape使用等手段就可以基本消除过渡绘制,减少对GPU和CPU的浪费。
优化图片框架
在listview 滑动时 ,图片框架不向listview 中的imageview 放入bitmap,listview 停下时 在向listview 中的imageview 放入bitmap。这些可以避免过度频繁执行imageview 的ondraw操作导致 卡顿
优化动画细节
一些Banner轮播广告和文字动画在移出可视区域后,仍然存在定时刷新,不仅耗电也影响帧率。优化措施是在移出可视区域后停止动画轮播
提前inflate
另外我们还通过提前inflate以及在线程中做一些必要的inflate等来提前初始化布局,减少实际显示时候的耗时。对于一些复杂的布局,我们还会自己做复用池,减少inflate带来的性能损耗,特别是在列表中。
阻断多余requestLayout
在ListView滑动,广告动画变化等过程中,图片和文字有变化,经常会发现整个界面被重新布局,影响了性能。尤其布局复杂时,测量过程很费时导致明显卡顿。对于大小基本固定的控件和布局例如TextView,ImageView来说,这是多余的损耗。我们可以用自定义控件来阻断,重写方法requestLayout、onSizeChanged,如果大小没有变化就阻断这次请求。对于ViewPager等广告条,可以设置缓存子view的数量为广告的数量