安卓渲染机制(Android开发之路论对渲染机制)
安卓渲染机制(Android开发之路论对渲染机制)● 24fps由于人类眼睛的特殊生理结构,如果所看画面之帧率高于每秒约 10 - 12fps 的时候,就会认为是连贯的。早期的无声电影的帧率介于 16 - 24fps 之间,虽然帧率足以让人感觉到运动,但往往被认为是在快放幻灯片。在 1920 年代中后期,无声电影的帧率提高到 20 - 26fps 之间。如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面;大多数手机的屏幕刷新频率是60hz,如果在1000/60=16.67ms内没有办法把这一帧的任务执行完毕,就会发生丢帧的现象。丢帧越多,用户感受到的卡顿情况就越严重一个 Android 应用是否流畅,或者说是否存在卡顿、丢帧现象,都与 60fps 和 16ms 有关;那么这两个值是怎么来的呢?为什么以这两个值为衡量标准呢?● 12fps(帧/
前言在 Android 开发行业工作有一段时间了,随着时间的增长,越发感觉自己的技术没有很大的长进,在平时也没有注意学习,只是完成了工作任务就可以了,这样下去的话,自己将很难有提高;面对现在激烈的竞争环境以及技术不断的更新,自己真的要去学习,不断的提高自己的技能,于是在今年年初就已经开始记录自己的学习笔记,技术总结,感受等,今天就向大家分享关于 Android 渲染机制的相关问题,相信这对自己也是对大家会有很大的益处
渲染性能大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验
但是Android系统很有可能无法及时完成那些复杂的界面渲染操作
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成
如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面;大多数手机的屏幕刷新频率是60hz,如果在1000/60=16.67ms内没有办法把这一帧的任务执行完毕,就会发生丢帧的现象。丢帧越多,用户感受到的卡顿情况就越严重
16ms原则一个 Android 应用是否流畅,或者说是否存在卡顿、丢帧现象,都与 60fps 和 16ms 有关;那么这两个值是怎么来的呢?为什么以这两个值为衡量标准呢?
● 12fps(帧/秒)
由于人类眼睛的特殊生理结构,如果所看画面之帧率高于每秒约 10 - 12fps 的时候,就会认为是连贯的。早期的无声电影的帧率介于 16 - 24fps 之间,虽然帧率足以让人感觉到运动,但往往被认为是在快放幻灯片。在 1920 年代中后期,无声电影的帧率提高到 20 - 26fps 之间。
● 24fps
1926 年有声电影推出,人耳对音频的变化更敏感,反而削弱了人对电影帧率的关注。因为许多无声电影使用 20 - 26fps 播放,所以选择了中间值 24fps 作为有声电影的帧率。之后 24fps 成为 35mm 有声电影的标准。
● 30fps
早期的高动态电子游戏,帧率少于每秒 30fps 的话就会显得不连贯。这是因为没有动态模糊使流畅度降低。(注:如果需要了解动态模糊技术相关知识,可以查阅 这里)
● 60fps
在实际体验中,60fps 相对于 30fps 有着更好的体验。
● 85fps
一般而言,大脑处理视频的极限
所以,总体而言,帧率越高体验越好
渲染优化首先我们来分析一下造成UI卡顿常见的原因有哪些:
● 在UI线程中做轻微耗时操作
● Layout过于复杂,无法在16ms中完成渲染
● 同一时间动画执行次数过多,造成CPU或GPU负载过重
● View过渡绘制,某一像素在同一帧重复绘制
● View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染
● 内存频繁触发GC过多(同一帧中频繁创建内存),导致暂时阻塞渲染操作
● 冗余资源及逻辑等导致加载和执行缓慢
● ANR
综上所述,我们感受到的卡顿问题大多都是因为渲染性能,Android系统每隔16ms发出VSYNC信号(vertical synchronization --场扫描同步,场同步,垂直同步),触发对UI进行渲染,
如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms(1000/60=16.67ms)内完成。如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象;那么用户在32ms内看到的会是同一帧画面,造成卡顿
布局优化Android需要把XML布局文件转换成GPU能够识别并绘制的对象;这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息;在某个View第一次需要被渲染时,DisplayList会因此而被创建,当这个View要显示到屏幕上时,我们会执行GPU的绘制指令来进行渲染
如果你修改了View中的某些可见组件,那么之前的DisplayList就无法继续使用了,我们需要回头重新创建一个DisplayList并且重新执行渲染指令并更新到屏幕上
布局太过复杂,层级嵌套太深导致绘制操作耗时,且增加内存的消耗;我们的目标就是,层级扁平化
布局优化主要从以下几个方面使用效率更高的布局方式,如线性布局、帧布局
● 能用LinearLayout和FrameLayout,就不要用RelativeLayout,因为RelativeLayout控件相对比较复杂,测绘也想要耗时。如果使用相对布局减少层级的就使用相对布局;
减少不必要的布局层级
● 这里就不得不提到include和merge标签了
include 可以提高布局的复用性,优化了布局的层级结构,使得布局结构清晰,但实际上include并没有减少布局的层级,所以include必须和merge同时使用,方可减少布局层级
惰性加载又称延迟加载
● 使用惰性控件ViewStub实现布局动态加载
ViewStub它可以按需加载,这个标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能;通常情况下我们需要在某个条件下使用某个布局的时候会通过gone或者invisible来隐藏
其实这样的方式虽然隐藏了布局,但是当显示该界面的时候还是将该布局实例化的。使用ViewStub可以避免内存的浪费,加快渲染速度。其实ViewStub就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才会将其要装载的目标布局给加载出来,从而达到延迟加载的效果,这个要被加载的布局通过android:layout属性来设置
使用ConstraintLayout布局 ● ConstraintLayout可以有效地解决布局嵌套过多的问题
ConstraintLayout使用约束的方式来指定各个控件的位置和关系的,它有点类似于 RelativeLayout,但远比RelativeLayout要更强大(照抄隔壁IOS的约束布局);简单布局简单处理,复杂布局ConstraintLayout很好使,提升性能从布局做起
有需要文档的同学,可以顺手给我点赞评论支持一下
资料获取方式:私信我发送“进阶”免费获取
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉
PS:有问题欢迎指正 欢迎大家点赞评论,可以在评论区留下你的建议和感受