标签:
每当一款App开始快速扩展的时候,随着业务功能的越来越复杂,功能模块的越来越多总会引起这样那样的性能问题。交互不流畅卡顿,ANR,手机发热量大等等性能问题在Android开发中一直都是一个坑爹的存在。不是大家不想去优化,可能是等你发现开始要搞搞性能的时候,发现工程貌似好大了,能跑不崩就万事大吉了,那么多代码要去看,去改。真心是一个让人想想都糟心的事。也可能,关键点不好找,可能一个性能问题是别的你想都想不到的地方引起的,为了优化这么一个点,可能花费很多时间。总之这么一个复杂,浩大的工作,如果不想做,可以找一万个理由。但是一款精品应用,性能优化会直接影响到你的app是一款什么层次的app,会有多少用户追捧你,可以让你的app提升多少价值。好了,不扯犊子了,言归正传。
本期说的是视图优化,那有几个关于渲染的基本概念就不得不提。
大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。当需求是一些复杂的交互或者是狂拽酷帅屌炸天的特效的时候,Android系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。
但是如上所说,如果一个屌炸天的效果处理超过了16ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。
一般来说UI执行动画、或者一个视图突然同时冒出来很多个需要渲染的组件、或者滑动ListView的时候容易引起卡顿,是因为这里的操作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原因可以导致丢帧,也许是因为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的绘制单元,还有可能是因为动画执行的次数过多。这些都会导致CPU或者GPU负载过重。
Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。
一般来说,这个问题应该是大多数app中都普遍存在的问题,可能是层叠组件的使用不合理导致过度重绘,也可能是Layout重复设置背景引起过度重绘。不过这个问题,我们可以很容易的借助手机提供的工具快速的找出来。之后给出工具的使用。
理解App是如何进行渲染的,我们必须了解手机硬件是如何工作,那么就必须理解什么是VSYNC。
在讲解VSYNC之前,我们需要了解两个相关的概念:
GPU会获取图形数据进行渲染,然后硬件负责把渲染后的内容呈现到屏幕上,他们两者不停的进行协作。
正常情况这样固然是好,但是问题就是,你程序中的操作,极有可能导致帧率不同步,导致前帧跟后帧重叠,出现图像断裂这样的问题。
就像下面这个图
VSYNC如果要深究还是蛮有意思的,有兴趣的可自行GOOGLE。分享一个VSYNC相关文献。
VSYNC 参考文献
http://blog.csdn.net/michaelcao1980/article/details/43233765
,图越高表示花费的渲染时间越长。
中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条
举个应用实例
用户中心有个活动标签的小动画即一个热门标签的抖动。进入到页面的时候,发现曲线跳动很厉害,而且每次跳动都超过16ms的基准线。就怀疑是否是这个动画效果实现的不合理。
经过审查代码发现如此简单的一个动画,采用的居然是逐帧动画的方式实现。
<span style="font-family:Comic Sans MS;font-size:14px;"><?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/hot_1" android:duration="200"/> <item android:drawable="@drawable/hot_2" android:duration="200"/> <item android:drawable="@drawable/hot_3" android:duration="200"/> </animation-list></span>
对于这种抖动的简单动画,完全可以用补间动画来做,不仅减少了资源的消耗,还可以让整个动画开起来更加流畅。
<pre name="code" class="java"><span style="font-family:Comic Sans MS;font-size:14px;"> private void setHotImgAnimation(View animationView){ ObjectAnimator shakeAnimator = new ObjectAnimator(); shakeAnimator.setInterpolator(new LinearInterpolator()); shakeAnimator.setProperty(View.ROTATION); shakeAnimator.setFloatValues(0,45,0); shakeAnimator.setDuration(600); shakeAnimator.setRepeatCount(ValueAnimator.INFINITE); shakeAnimator.setTarget(animationView); shakeAnimator.start(); }</span>
运行代码看修改后的效果:
从图中可以明显看出GPU呈现的分析图,整个过程变得相对平滑,动画过程也都降到了16ms以下。
Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加蓝色区域的占比。这一措施能够显著提升程序性能。
注:为了更好的呈现OverDraw所带来的性能影响,这里做了个小动作——不停的刷新界面,以便的到充足的GPU性能分析图。
从图中可看出,左边未修改的界面,OverDraw严重,满屏幕飙红,从GPU呈现图上来看,GPU平局渲染时间都超过了16ms的基准。上图造成如此多的过度绘制的主要原因是重复的背景,红色区域上层布局设置了背景,子布局又重复设置背景,导致了过度绘制。将不必要的背景设置出去以后,可以看到,红色标记区域基本消失,从GPU呈现图上来看,GPU平均渲染时间也降低到了16ms的基准线以下。
标签:
原文地址:http://blog.csdn.net/shenjinalin123/article/details/51982794