Android 性能优化之减小UI过分绘制

什么是过分绘制(OverDraw)


在多层次重叠的UI结构里面,若是不可见的UI也在作绘制的操做,会致使某些像素区域被绘制了屡次。这样就会浪费大量的CPU以及GPU资源。过分绘制最直观的影响就是会致使APP卡顿。还好系统有提供GPU过分绘制调试工具会在屏幕上用不一样的颜色,来代表一个像素点位被重复绘制的次数。android

怎样开启GPU过分绘制调试工具?

1.点击进入“设置”;
2.点击进入“开发者选项”
3.选中“调试GPU过分绘制”
4.选中“显示过分绘制区域”canvas

此时,你会注意到屏幕的颜色变化了,别紧张。切换到你的应用,如今咱们开始了解怎么经过改善布局来解决过分绘制问题。缓存

屏幕上不一样的颜色表明着什么?

1.原色没有被过分绘制 – 这部分的像素点只在屏幕上绘制了一次。
2.蓝色1次过分绘制– 这部分的像素点只在屏幕上绘制了两次。
3.绿色2次过分绘制 – 这部分的像素点只在屏幕上绘制了三次。
4.粉色3次过分绘制 – 这部分的像素点只在屏幕上绘制了四次。
5.红色4次过分绘制 – 这部分的像素点只在屏幕上绘制了五次。工具

怎么解决应用过分绘制?

由上面的知识,咱们知道要解决过分绘制。便是要尽可能减小屏幕上的红色区域,增长屏幕上的蓝色和绿色区域。咱们的目标是要控制界面最多被过分绘制2次(不出现粉色和红色)。布局

1.合理选择控件容器
既然overdraw是由于重复绘制了同一片区域的像素点,那咱们首先想到的是解决布局问题。Android提供的Layout控件主要包括LinearLayout、TableLayout、FrameLayout、RelativeLayout(这里咱们不考虑AbsoluteLayout)。同一个界面咱们可使用不一样的容器控件来表达,可是各个容器控件描述界面的复杂度是不同的。通常来讲LinearLayout最易,RelativeLayout较复杂。可是尺有所短,寸有所长,LinearLayout只能用来描述一个方向上连续排列的控件,容易致使布局文件嵌套太深,不符合布局扁平化的设计原理。而RelativeLayout几乎能够用于描述任意复杂度的界面。可是表达能力越强的容器控件,性能每每略低一些,由于RelativeLayout主要在onMeasure和onLayout阶段会耗费更多时间。综上所述:LinearLayout易用,效率高,表达能力有限。RelativeLayout复杂,表达能力强,可是效率稍逊。因此当某一界面在使用LinearLayout并不会比RelativeLayout带来更多的控件数和控件层级时,咱们要优先考虑LinearLayout。可是要根据实际状况来作一个取舍,在保证性能的同时尽可能避免OverDraw。性能


2.去掉window的默认背景
当咱们使用了Android自带的一些主题时,window会被默认添加一个纯色的背景,这个背景是被DecorView持有的。当咱们的自定义布局时又添加了一张背景图或者设置背景色,那么DecorView的background此时对咱们来讲是无用的,可是它会产生一次Overdraw,带来绘制性能损耗。去掉window的背景能够在onCreate()中setContentView()以后调用
getWindow().setBackgroundDrawable(null);优化

或者在theme中添加
android:windowbackground="null";ui


3.去掉其余没必要要的背景
有时候为了方便会先给Layout设置一个总体的背景,再给子View设置背景,这里也会形成重叠,若是子View宽度mach_parent,能够看到彻底覆盖了Layout的一部分,这里就能够经过分别设置背景来减小重绘。再好比若是采用的是selector的背景,将normal状态的color设置为“@android:color/transparent",也一样能够解决问题。这里只简单举两个例子,咱们在开发过程当中的一些习惯性思惟定式会带来不经意的Overdraw,因此开发过程当中咱们为某个View或者ViewGroup设置背景的时候,先思考下是否真的有必要,或者思考下这个背景能不能分段设置在子View上,而不是图方便直接设置在根View上。spa


4.ClipRect & QuickReject
为了解决Overdraw的问题,Android系统会经过避免绘制那些彻底不可见的组件来尽可能减小消耗。可是不幸的是,对于那些过于复杂的自定义的View(一般重写了onDraw方法),Android系统没法检测在onDraw里面具体会执行什么操做,系统没法监控并自动优化,也就没法避免Overdraw了。可是咱们能够经过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法能够指定一块矩形区域,只有在这个区域内才会被绘制,其余的区域会被忽视。这个API能够很好的帮助那些有多组重叠组件的自定义View来控制显示的区域。同时clipRect方法还能够帮助节约CPU与GPU资源,在clipRect区域以外的绘制指令都不会被执行,那些部份内容在矩形区域内的组件,仍然会获得绘制。除了clipRect方法以外,咱们还可使用canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操做。
clip方法详解设计


5.使用ViewStub占位
ViewStub是个什么东西?一句话总结:高效占位符。咱们常常会遇到这样的状况,运行时动态根据条件来决定显示哪一个View或布局。经常使用的作法是把View都写在上面,先把它们的可见性都设为View.GONE,而后在代码中动态的更改它的可见性。这样的作法的优势是逻辑简单并且控制起来比较灵活。可是它的缺点就是,耗费资源。虽然把View的初始可见View.GONE可是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会建立对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。推荐的作法是使用android.view.ViewStub,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源很是小的控件。能够为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,而后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局就会被Inflate和实例化,而后ViewStub的布局属性都会传给它所指向的布局。这样,就可使用ViewStub来方便的在运行时,要仍是不要显示某个布局。

当你想加载布局时,可使用下面其中一种方法:


6.用Merge减小布局深度
Merge标签有什么用呢?简单粗暴点回答:干掉一个view层级。Merge的做用很明显,可是也有一些使用条件的限制。有两种状况下咱们可使用Merge标签来作容器控件。第一种子视图不须要指定任何针对父视图的布局属性,就是说父容器仅仅是个容器,子视图只须要直接添加到父视图上用于显示就行。另一种是假如须要在LinearLayout里面嵌入一个布局(或者视图),而偏偏这个布局(或者视图)的根节点也是LinearLayout,这样就多了一层没有用的嵌套,无疑这样只会拖慢程序速度。而这个时候若是咱们使用merge根标签就能够避免那样的问题。另外Merge只能做为XML布局的根标签使用,当Inflate以<merge />开头的布局文件时,必须指定一个父ViewGroup,而且必须设定attachToRoot为true。
使用HierarchyViewer检查布局层级


7.善用draw9patch
给ImageView加一个边框,你确定遇到过这种需求,一般在ImageView后面设置一张背景图,露出边框便完美解决问题,此时这个ImageView,设置了两层drawable,底下一层仅仅是为了做为图片的边框而已。可是两层drawable的重叠区域去绘制了两次,致使overdraw。优化方案: 将背景drawable制做成draw9patch,而且将和前景重叠的部分设置为透明。因为Android的2D渲染器会优化draw9patch中的透明区域,从而优化了此次overdraw。 可是背景图片必须制做成draw9patch才行,由于Android 2D渲染器只对draw9patch有这个优化,不然,一张普通的Png,就算你把中间的部分设置成透明,也不会减小此次overdraw。


8.慎用Alpha
假如对一个View作Alpha转化,须要先将View绘制出来,而后作Alpha转化,最后将转换后的效果绘制在界面上。通俗点说,作Alpha转化就须要对当前View绘制两遍,可想而知,绘制效率会大打折扣,耗时会翻倍,因此Alpha仍是慎用。若是必定作Alpha转化的话,能够采用缓存的方式。

经过setLayerType方式能够将当前界面缓存在GPU中,这样不须要每次绘制原始界面,可是GPU内存是至关宝贵的,因此用完要立刻释放掉。


9.避免“OverDesign” overdraw会给APP带来很差的体验,overdraw产生的缘由无外乎:复杂的Layout层级,重叠的View,重叠的背景这几种。开发人员无节制的View堆砌,究其根本无非是产品无节制的需求设计。有道是“由俭入奢易,由奢入俭难",不少APP披着过分设计的华丽外衣,却忘了简单易用才是王道的本质,纷繁复杂的设计并不会给用户带来好的体验,反而会让用户有压迫感,产品自己也有可能所以变得卡顿。固然,一切抛开业务谈优化都是空中楼阁,这就须要产品设计也要有一个权衡,在复杂的业务逻辑与简单易用的界面展示中作一个平衡,而不是一味的OverDesign。

做者:Rave_Tian 连接:https://www.jianshu.com/p/2cc6d5842986 來源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。
相关文章
相关标签/搜索