除了Bug,最让你头疼的问题是什么?单身?秃头?996?面试造火箭,工作拧螺丝?

作为安卓开发者,除了Bug,经常会碰到下面这些问题:

应用卡顿,丢帧,屏幕画面撕裂,操作界面刷新缓慢,UI不美观,布局混乱…这些问题频发的话,年后可能就不用来了。

开发App的时候,你是否会觉得界面卡顿?尤其是自定义View的时候。

Android 应用的卡顿、丢帧等,这些影响用户体验的因素绝大部分都与 16ms 这个值有关。Android 设备的刷新率也是 60Hz,Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果超过了16ms,我们则认为发生了卡顿。

二、显示系统基础知识

在一个典型的显示系统中,一般包括CPU、GPU、Display三个部分, CPU负责计算帧数据,把计算好的数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到buffer(图像缓冲区)里存起来,然后Display(屏幕或显示器)负责把buffer里的数据呈现到屏幕上。如下图:

2.1 基础概念

  • 屏幕刷新频率 一秒内屏幕刷新的次数(一秒内显示了多少帧的图像),单位 Hz(赫兹),如常见的 60 Hz。刷新频率取决于硬件的固定参数(不会变的)。

  • 逐行扫描 显示器并不是一次性将画面显示到屏幕上,而是从左到右边,从上到下逐行扫描,顺序显示整屏的一个个像素点,不过这一过程快到人眼无法察觉到变化。以 60 Hz 刷新率的屏幕为例,这一过程即 1000 / 60 ≈ 16ms。

  • 帧率 (Frame Rate) 表示 GPU 在一秒内绘制操作的帧数,单位 fps。例如在电影界采用 24 帧的速度足够使画面运行的非常流畅。而 Android 系统则采用更加流程的 60 fps,即每秒钟GPU最多绘制 60 帧画面。帧率是动态变化的,例如当画面静止时,GPU 是没有绘制操作的,屏幕刷新的还是buffer中的数据,即GPU最后操作的帧数据。

  • 画面撕裂(tearing) 一个屏幕内的数据来自2个不同的帧,画面会出现撕裂感,如下图

2.2 双缓存

2.2.1 画面撕裂 原因

屏幕刷新频是固定的,比如每16.6ms从buffer取数据显示完一帧,理想情况下帧率和刷新频率保持一致,即每绘制完成一帧,显示器显示一帧。但是CPU/GPU写数据是不可控的,所以会出现buffer里有些数据根本没显示出来就被重写了,即buffer里的数据可能是来自不同的帧的, 当屏幕刷新时,此时它并不知道buffer的状态,因此从buffer抓取的帧并不是完整的一帧画面,即出现画面撕裂。

简单说就是Display在显示的过程中,buffer内数据被CPU/GPU修改,导致画面撕裂。

2.2.2 双缓存

那咋解决画面撕裂呢? 答案是使用 双缓存。

由于图像绘制和屏幕读取 使用的是同个buffer,所以屏幕刷新时可能读取到的是不完整的一帧画面。

双缓存,让绘制和显示器拥有各自的buffer:GPU 始终将完成的一帧图像数据写入到 Back Buffer,而显示器使用 Frame Buffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。如下图:

2.2.3 VSync

问题又来了:什么时候进行两个buffer的交换呢?

假如是 Back buffer准备完成一帧数据以后就进行,那么如果此时屏幕还没有完整显示上一帧内容的话,肯定是会出问题的。看来只能是等到屏幕处理完一帧数据后,才可以执行这一操作了。

当扫描完一个屏幕后,设备需要重新回到第一行以进入下一次的循环,此时有一段时间空隙,称为VerticalBlanking Interval(VBI)。那,这个时间点就是我们进行缓冲区交换的最佳时间。因为此时屏幕没有在刷新,也就避免了交换过程中出现 screen tearing的状况。

VSync(垂直同步)是VerticalSynchronization的简写,它利用VBI时期出现的vertical sync pulse(垂直同步脉冲)来保证双缓冲在最佳时间点才进行交换。另外,交换是指各自的内存地址,可以认为该操作是瞬间完成。

所以说V-sync这个概念并不是Google首创的,它在早年的PC机领域就已经出现了。

三、Android屏幕刷新机制

3.1 Android4.1之前的问题

具体到Android中,在Android4.1之前,屏幕刷新也遵循 上面介绍的 双缓存+VSync 机制。如下图:

以时间的顺序来看下将会发生的过程:

  1. Display显示第0帧数据,此时CPU和GPU渲染第1帧画面,且在Display显示下一帧前完成
  2. 因为渲染及时,Display在第0帧显示完成后,也就是第1个VSync后,缓存进行交换,然后正常显示第1帧
  3. 接着第2帧开始处理,是直到第2个VSync快来前才开始处理的。
  4. 第2个VSync来时,由于第2帧数据还没有准备就绪,缓存没有交换,显示的还是第1帧。这种情况被Android开发组命名为“Jank”,即发生了丢帧
  5. 当第2帧数据准备完成后,它并不会马上被显示,而是要等待下一个VSync 进行缓存交换再显示。

所以总的来说,就是屏幕平白无故地多显示了一次第1帧。

原因是 第2帧的CPU/GPU计算 没能在VSync信号到来前完成 。

我们知道,双缓存的交换 是在Vsyn到来时进行,交换后屏幕会取Frame buffer内的新数据,而实际 此时的Back buffer 就可以供GPU准备下一帧数据了。 如果 Vsyn到来时 CPU/GPU就开始操作的话,是有完整的16.6ms的,这样应该会基本避免jank的出现了(除非CPU/GPU计算超过了16.6ms)。 那如何让 CPU/GPU计算在 Vsyn到来时进行呢?

3.2 drawing with VSync

为了优化显示性能,Google在Android 4.1系统中对Android Display系统进行了重构,实现了Project Butter(黄油工程):系统在收到VSync pulse后,将马上开始下一帧的渲染。即一旦收到VSync通知(16ms触发一次),CPU和GPU 才立刻开始计算然后把数据写入buffer。如下图:

CPU/GPU根据VSYNC信号同步处理数据,可以让CPU/GPU有完整的16ms时间来处理数据,减少了jank。

一句话总结,VSync同步使得CPU/GPU充分利用了16.6ms时间,减少jank。

问题又来了,如果界面比较复杂,CPU/GPU的处理时间较长 超过了16.6ms呢?如下图:

  1. 在第二个时间段内,但却因 GPU 还在处理 B 帧,缓存没能交换,导致 A 帧被重复显示。
  2. 而B完成后,又因为缺乏VSync pulse信号,它只能等待下一个signal的来临。于是在这一过程中,有一大段时间是被浪费的。
  3. 当下一个VSync出现时,CPU/GPU马上执行操作(A帧),且缓存交换,相应的显示屏对应的就是B。这时看起来就是正常的。只不过由于执行时间仍然超过16ms,导致下一次应该执行的缓冲区交换又被推迟了——如此循环反复,便出现了越来越多的“Jank”。

为什么 CPU 不能在第二个 16ms 处理绘制工作呢?

原因是只有两个 buffer,Back buffer正在被GPU用来处理B帧的数据, Frame buffer的内容用于Display的显示,这样两个buffer都被占用,CPU 则无法准备下一帧的数据。 那么,如果再提供一个buffer,CPU、GPU 和显示设备都能使用各自的buffer工作,互不影响。

3.3 三缓存

三缓存就是在双缓冲机制基础上增加了一个 Graphic Buffer 缓冲区,这样可以最大限度的利用空闲时间,带来的坏处是多使用的一个 Graphic Buffer 所占用的内存。

  1. 第一个Jank,是不可避免的。但是在第二个 16ms 时间段,CPU/GPU 使用 第三个 Buffer 完成C帧的计算,虽然还是会多显示一次 A 帧,但后续显示就比较顺畅了,有效避免 Jank 的进一步加剧。

  2. 注意在第3段中,A帧的计算已完成,但是在第4个vsync来的时候才显示,如果是双缓冲,那在第三个vynsc就可以显示了。

三缓冲有效利用了等待vysnc的时间,减少了jank,但是带来了延迟。 所以,是不是 Buffer 越多越好呢?这个是否定的,Buffer 正常还是两个,当出现 Jank 后三个足以。

以上就是Android屏幕刷新的原理了。

小结

有了这么多优秀的开发工具,可以做出更高质量的Android应用。

当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。

在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

oid开发面试专题资料,高级进阶架构资料**这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

如果你有需要的话,可以点击这里领取

终于有人把安卓程序员必学知识点全整理出来了,送大厂面经一份!相关推荐

  1. 终于有人把安卓程序员必学知识点全整理出来了,BAT大厂面试总结

    行业激烈变化时,恰恰是机会最多的时候 坦白讲,许多人骨子里害怕变化和竞争. 其实大可不必. 一来,怕也没用嘛.二来,变化越快,组合要素增加了,意味着新的工作机会越多. 就像传统媒体VS新媒体. 放在1 ...

  2. Android面试总结,终于有人把安卓程序员必学知识点全整理出来了,移动架构师成长路线

    前言 这篇文章主要是分享今年面试心得,现已就职于某大厂有三个月了,近期有很多公司均已启动秋招,也祝大家面试顺利,获得理想的offer! 之前找工作的那段时间感想颇多,总结一点面试经验和人生思考分享给大 ...

  3. 安卓开发入门教程!终于有人把安卓程序员必学知识点全整理出来了,附答案

    如何提升学习? 提升学习很大程度上就是为了跳槽涨薪,当然运气不好的情况可能是被劝退重新找工作,无论是哪种情况,自主学习的能力是要有的,而且得有一个方向,得有重点. 对于Android移动开发来说,热修 ...

  4. java基础案例教程课后答案,终于有人把Java程序员必学知识点全整理出来了

    前言 微架构的出现,很好地适应了这个时代对快速发展变化的要求.它不再提倡一体化的项目设计,而是对项目进行有效的"业务区"(可以简单理解为不同的子系统〉划分,并利用合理的技术对业务性 ...

  5. 来电通java版_终于有人把Java程序员必学知识点整理出来了,令人有如醍醐灌顶...

    JVM 无论什么级别的Java从业者,JVM都是进阶时必须迈过的坎.不管是工作还是面试中,JVM都是必考题.如果不懂JVM的话,薪酬会非常吃亏(近70%的面试者挂在JVM上了) 详细介绍了JVM有关于 ...

  6. 终于有人把Java程序员必学知识点整理出来了,令人有如醍醐灌顶

    JVM 无论什么级别的Java从业者,JVM都是进阶时必须迈过的坎.不管是工作还是面试中,JVM都是必考题.如果不懂JVM的话,薪酬会非常吃亏(近70%的面试者挂在JVM上了) 详细介绍了JVM有关于 ...

  7. 成为高级程序员必学知识点!

    技术选型 网关:Nginx.Kong.Zuul 缓存:Redis.MemCached.OsCache.EhCache 搜索:ElasticSearch.Solr 熔断:Hystrix.resilien ...

  8. java在容器中导入图片_Java程序员必学技术:@Import直接导入类,在容器@Configuration、@Component中是怎么直接导入类注册到容器的?...

    Java程序员必学技术:@Import直接导入类,在容器@Configuration.@Component中是怎么直接导入类注册到容器的? Spring IoC 容器是一个管理 Bean 的容器,在 ...

  9. 程序员初级计算机专业英语词汇,程序员必学计算机专业英语词汇

    程序员必学计算机专业英语词汇 (98页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 21.9 积分 程序员必学电脑计算机专业英语词汇F订cn.档案,公文箱 ...

最新文章

  1. centos安装及网络配置
  2. linux下QT Creator常见错误及解决办法
  3. gitpythonapi_GitPython 使用基础
  4. redis java应用_Java+Redis应用(第一章)
  5. js代码计算济南出租车打车费用
  6. YBTOJ:矛盾指数(网络流-最大权闭合图)
  7. 认识linux,走进开源世界。
  8. dqo变换_一种基于dqo变换改进的电流检测新方法
  9. 宿舍物联网门锁系统之个人小程序注册
  10. three.js特效
  11. 旋转Kubernetes中的秘密
  12. 2 什么是计算机网络的拓扑结构,什么是网络拓扑?
  13. DeepFM 参数理解(二)
  14. 各种域名都代表什么意思?
  15. 赛尔号和赛尔机器人_赛尔号大电影6垃圾星赛尔机器人介绍
  16. 【DIY】制作一个刷卡进门装置
  17. mysql按某个条件升序_问题描述大家都知道, MySQL 中按某字段升序排列的 SQL 为 (以 id 为例,下同):SELECT * FROM `MyTable` WHERE...
  18. TheProjetXXXXXneedstobedeployedbeforeitanbestarted
  19. python之获取本机ip
  20. H.264编码四种画质级别

热门文章

  1. Web开发常出现的错误[个人收集]
  2. java的ZipOutputStream压缩文件的两个问题(乱码和每次zip后文件md5变化)
  3. matlab 多文件编程,是否有可能在MATLAB中为每个文件定义多个函数,并从该文件外部访问它们?...
  4. python去掉重复内容并按原来次序输出元素_在Python中,从列表中删除重复项以使所有元素在保留顺序时都是唯一的最快的算法是什么?...
  5. mysql 5.6.23免安装_mysql5.6.23免安装配置
  6. linux里hba状态_Windows和Linux系统查看HBA卡wwn号的方法 | 系统之家官网
  7. Tomcat 6连接池配置
  8. 转载|网络编程中阻塞式函数的底层逻辑
  9. leetcode 538. 把二叉搜索树转换为累加树 思考分析
  10. 安卓log.e函数打印示例_log1p()函数以及C ++中的示例