V-Sync和FreeSync、G-Sync有什么区别?各自有什么优缺点?
在V-Sync中,显示器较为主动,显卡较为被动。显示器被设置为每隔1/60秒想显卡索要一次信息。如果显卡能每次都能在1/60秒内将信息准备完毕,那么桌面就不会出现卡顿,但是显卡不能将信息准备好,那么就会出现卡顿。在V-Sync的过程中,显卡一直处于比较被动的过程,必须等待显示器发出的同步信号之后才会绘制下一帧的内容。
G-Sync是为了在出现卡顿时,让显示器稍微等一下,比如下一帧是1/50秒后才画出来,那显示器就等上1/50秒再刷新画面。
举了粒子吧(Copy From Zhihu):
有俩穷逼双胞胎兄弟分别在外面租房子住,拿画抵房租,假设他们绘图进度完全一致(即上图的红色竖线)。
哥哥的房东V-Sync是个机器收租人,他雷打不动地每个月1号都去问你要房租,如果你画好了他就收租,没画完他就下个月1号再来。所以他家里挂着的是A画,(一个月后)B画,(一个月后)B画,(一个月后)C画。
弟弟的房东G-Sync是个慈祥的老奶奶,她从来不主动找你收租,你画好画后,如果距离上次缴房租大于等于一个月你就马上给她。如果距离上次缴房租时间还不到一个月,老奶奶则坚持要过完一个月后才收你的画。多么可爱的老奶奶!所以老奶奶家里挂着的是A画,(一个月后)B画,(34天后)C画,(一个月后)D画。 大家就说哇老奶奶你家的画好新鲜,好繁多喔!(/▽╲)
可见,明明是同等的绘画情况下,慈祥老奶奶家里挂着的画切换更频繁!也更即时! 这个故事告诉我们一个道理,好人会有好报,如若对待生活窘迫的人要多一点理解和宽容,也许会收获许多意想不到的喜悦……
FPS与流畅度的关系?24帧为什么不够?
FPS:Frame Per Second,即每秒所需要更新的帧数。在系统更新每一帧时,首先会将系统内现在正在运行的所有运行的进程需要展示的信息合成一帧,然后将其展示在屏幕上。综上,FPS就是指系统每秒提交到屏幕的帧数。因此系统的绘制需求低时,FPS就会低;当系统绘制需求高时,FPS就得高。如果系统绘制需求高但FPS低就会出现卡顿现象。
可见,FPS不是由单一进程来决定的,它取决于当前系统的所有进程。因此我们不操作屏幕时,FPS也不会为0,这是因为可能会有其他进程正在绘制屏幕,例如状态栏。
当FPS接近60时,不管系统的绘制需要如何,用户都不会感到卡顿;FPS较低时,用户能否感觉到卡顿,取决于当前系统的绘制需求。
如果以24FSP播放电影,我们并不会觉得卡顿,这是因为什么呢?原因很简单,这是因为影片的每一帧都是连续的,而App的每一帧并不是连续的。
影响流畅度的几个指标
- 过度绘制
- 布局层级过深
如何改善App流畅度
解决过度绘制
什么是过度绘制?过度绘制有什么缺点?会造成什么样的影响?
过度绘制是指在屏幕的同一处进行了多次绘制,但是上一次绘制总会被下一次绘制覆盖,因此上一次绘制是冗余的,我们将这种冗余绘制叫做过度绘制。
屏幕绘制最终是GPU来完成的,因此过度绘制会造成GPU绘制压力增大,整体表现为App性能低下,绘制速度慢,用户体验差。
如何识别过度绘制?
我们可以很轻易的识别出是否存在过度绘制,只需要在开发者选项中打开“显示GPU过度绘制”选项即可。
颜色标识: GPU过渡绘制从好到差:蓝-绿-淡红-红
- 蓝色1x过度绘制
- 绿色2x过度绘制
- 淡红色3x过度绘制
- 红色超过4x过度绘制
验收标准:
- 控制过度绘制为2x
- 不允许存在4x过度绘制
- 不允许存在面积超过屏幕1/4区域的3x过度绘制(淡红色区域)
什么会造成过度绘制呢?如何解决过度绘制?
- View本身多次绘制,可能是绘制背景和和绘制文字的重叠
- 多个View之间存在重叠。
优化布局层级
如何识别View层级过深?有什么工具?
1. View Hierarchy
通过View Hierarchy不仅可以查看每个View的层次,也可以看到每个View的measure,Layout,draw三个过程所需要的时间。如果测量、布局、绘制View较慢,则标记为红色,表明需要优化。
2. Trace for OpenGl ES
Trace for OpenGl Es可以逐帧分析GPU的绘制时间。
3. Lint(静态代码扫描分析器)
在android studio中的工具栏中选择Analyse-->Inspect Code,即可进行静态代码扫描。
Lint会分析上图中各个方面存在的问题,我们着重关注Performance这部分。在Performance中可能会存在以下16中问题:
- DrawAllocation:尽量避免在view绘制过程中分配对象(new)
- WakeLock:WakeLock会导致高耗电
- Recycle:释放资源,TypedArrays、VelocityTrackers等用完之后一定要回收;
- ObsoleteLayoutParam:Layout中无用的参数;
- UserCompoundDrawables:尽量利用TextView的drawable属性来减少TextView与ImageView处于同一层级。
- HandlerLeak:Handler导致的内存泄露
- UseSparseArrays:尽量使用SparseArray代替HashMap
- UseValueOf:使用常量对象时,尽量避免new,应该使用valueOf,这样可以节省内存。例如使用Integer.valueOf(10)而不是new Integer(10);
- DisableBaselineAlignment:如果LinearLayout被用作嵌套的Layout控件计算,它的android:baselineAligned属性应该置为false,以加快layout计算。
- InefficientWeight:当使用Weight属性时,应该讲layout_widht/layout_height设置为0dp,从而省略measure过程。
- FloatMath:使用FloatMath代替Math。
- NestedWeights:避免嵌套weight,否则会拖累执行效率;
- UnusedResources/UnusedIds:未使用的资源会使得App变大,且编译缓慢
- OverDraw:过度绘制
- UselessLeaf/UselessParent:view或view的parent无用;
- UnusedNamespace:无用命令空间,影响执行效率
此外,Lint还可自定义规则。
布局的三原则?
- 使用合并无用的父布局
- 使用实现按需加载,例如进度条、显示错误信息
- 尽量减少布局的层次深度