前言
手机屏幕是由许多的像素点组成的,每个像素点通过显示不同的颜色最终屏幕呈现各种各样的图像。手机系统的类型和手机硬件的不同导致UI的流畅性体验个不一致。

屏幕展示的颜色数据
在GPU中有一块缓冲区叫做 Frame Buffer ,这个帧缓冲区可以认为是存储像素值的二位数组。
数组中的每一个值就对应了手机屏幕的像素点需要显示的颜色。
由于这个帧缓冲区的数值是在不断变化的,所以只要完成对屏幕的刷新就可以显示不同的图像了.。
至于刷新工作手记的逻辑电路会定期的刷新 Frame Buffer的 目前主流的刷新频率为60次/秒 折算出来就是16ms刷新一次。
GPU的Frame Buffer中的数据
GPU 除了帧缓冲区用以交给手机屏幕进行绘制外. 还有一个缓冲区 Back Buffer 这个用以交给应用的,让CPU往里面填充数据。
GPU会定期交换 Back Buffer 和 Frame Buffer ,也就是对Back Buffer中的数据进行栅格化后将其转到 Frame Buffer 然后交给屏幕进行显示绘制,同时让原先的Frame Buffer 变成 Back Buffer 让程序处理。
Android的16ms
在Android中我们一般都会提到16ms绘制一次,那么到底是那里控制这16ms的呢?

在Choreographer类中我们有一个方法获取屏幕刷新速率:

public final class Choreographer {
    private static float getRefreshRate() {
        DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
                Display.DEFAULT_DISPLAY);
        return di.refreshRate;
    }
}

/**
 * Describes the characteristics of a particular logical display.
 * @hide
 */
public final class DisplayInfo implements Parcelable {
    /**
     * The refresh rate of this display in frames per second.
     * <p>
     * The value of this field is indeterminate if the logical display is presented on
     * more than one physical display.
     * </p>
     */
    public float refreshRate;
}

final class VirtualDisplayAdapter extends DisplayAdapter {
    private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
        @Override
        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
            if (mInfo == null) {
                mInfo = new DisplayDeviceInfo();
                mInfo.name = mName;
                mInfo.uniqueId = getUniqueId();
                mInfo.width = mWidth;
                mInfo.height = mHeight;
                mInfo.refreshRate = 60;
                /***部分代码省略***/
            }
            return mInfo;
        }
    }
}
一秒60帧,计算下来大概16.7ms一帧。

屏幕绘制
作为严重影响Android口碑问题之一的UI流畅性差的问题,首先在Android 4.1版本中得到了有效处理。其解决方法就是本文要介绍的Project Butter。

Project Butter对Android Display系统进行了重构,引入了三个核心元素,即VSYNC、Triple Buffer和Choreographer。其中, VSYNC是理解Project Buffer的核心。VSYNC是Vertical Synchronization(垂直同步)的缩写,是一种在PC上已经很早就广泛使用的技术。 可简单的把它认为是一种定时中断。

接下来,将围绕VSYNC来介绍Android Display系统的工作方式。请注意,后续讨论将以Display为基准,将其划分成16ms长度的时间段, 在每一时间段中,Display显示一帧数据(相当于每秒60帧)。时间段从1开始编号。

没有VSYNC的情况:

由上图可知

1.时间从0开始,进入第一个16ms:Display显示第0帧,CPU处理完第一帧后,GPU紧接其后处理继续第一帧。三者互不干扰,一切正常。 2.时间进入第二个16ms:因为早在上一个16ms时间内,第1帧已经由CPU,GPU处理完毕。故Display可以直接显示第1帧。显示没有问题。但在本16ms期间,CPU和GPU 却并未及时去绘制第2帧数据(注意前面的空白区),而是在本周期快结束时,CPU/GPU才去处理第2帧数据。 3.时间进入第3个16ms,此时Display应该显示第2帧数据,但由于CPU和GPU还没有处理完第2帧数据,故Display只能继续显示第一帧的数据,结果使得第1 帧多画了一次(对应时间段上标注了一个Jank)。 4.通过上述分析可知,此处发生Jank的关键问题在于,为何第1个16ms段内,CPU/GPU没有及时处理第2帧数据?原因很简单,CPU可能是在忙别的事情(比如某个应用通过sleep 固定时间来实现动画的逐帧显示),不知道该到处理UI绘制的时间了。可CPU一旦想起来要去处理第2帧数据,时间又错过了!

NSYNC的出现
为解决这个问题,Project Buffer引入了VSYNC,这类似于时钟中断。结果如图所示:


由图可知,每收到VSYNC中断,CPU就开始处理各帧数据。整个过程非常完美。 不过,仔细琢磨图2却会发现一个新问题:图2中,CPU和GPU处理数据的速度似乎都能在16ms内完成,而且还有时间空余,也就是说,CPU/GPU的FPS(帧率,Frames Per Second)要高于Display的FPS。确实如此。由于CPU/GPU只在收到VSYNC时才开始数据处理,故它们的FPS被拉低到与Display的FPS相同。但这种处理并没有什么问题,因为Android设备的Display FPS一般是60,其对应的显示效果非常平滑。 如果CPU/GPU的FPS小于Display的FPS,会是什么情况呢?请看下图:


由图可知: 1.在第二个16ms时间段,Display本应显示B帧,但却因为GPU还在处理B帧,导致A帧被重复显示。 2.同理,在第二个16ms时间段内,CPU无所事事,因为A Buffer被Display在使用。B Buffer被GPU在使用。注意,一旦过了VSYNC时间点, CPU就不能被触发以处理绘制工作了。

三级缓存
为什么CPU不能在第二个16ms处开始绘制工作呢?原因就是只有两个Buffer。如果有第三个Buffer的存在,CPU就能直接使用它, 而不至于空闲。出于这一思路就引出了Triple Buffer。结果如图所示:


由图可知: 第二个16ms时间段,CPU使用C Buffer绘图。虽然还是会多显示A帧一次,但后续显示就比较顺畅了。 是不是Buffer越多越好呢?回答是否定的。由图4可知,在第二个时间段内,CPU绘制的第C帧数据要到第四个16ms才能显示, 这比双Buffer情况多了16ms延迟。所以,Buffer最好还是两个,三个足矣。

以上对VSYNC进行了理论分析,其实也引出了Project Buffer的三个关键点: 核心关键:需要VSYNC定时中断。 Triple Buffer:当双Buffer不够使用时,该系统可分配第三块Buffer。 另外,还有一个非常隐秘的关键点:即将绘制工作都统一到VSYNC时间点上。这就是Choreographer的作用。在它的统一指挥下,应用的绘制工作都将变得井井有条。

Android的16ms和垂直同步以及三重缓存相关推荐

  1. 【总结】Android的16ms和垂直同步以及三重缓存

    前言 手机屏幕是由许多的像素点组成的,每个像素点通过显示不同的颜色最终屏幕呈现各种各样的图像.手机系统的类型和手机硬件的不同导致UI的流畅性体验个不一致. 屏幕展示的颜色数据 在GPU中有一块缓冲区叫 ...

  2. Android 显示刷新机制、VSYNC和三重缓存机制

    Android 显示刷新机制.VSYNC和三重缓存机制 为了理解 APP 是如何进行渲染的,我们就必须了解手机硬件是如何工作的,也必须理解什么是 VSYNC. 首先,我们需要了解2个相关概念: 刷新率 ...

  3. 游戏中的“垂直同步”与“三重缓冲”究竟是个啥?

    从今天开始,我们会开启"小教程"的兄弟栏目--小科普,给大家介绍在配电脑或玩游戏过程中经常会遇到的专业名词. 第一期"小科普"我们来讲讲游戏中经常会遇到的一个画 ...

  4. Android进阶之路 - 批量下载、缓存图片、视频

    之前已经记录过,批量下载图片和缓存本地的方式,此篇主要记录批量下载图片.视频,同时缓存在本地的功能实现 关联篇 Android进阶之路 - 批量下载.缓存图片 Android进阶之路 - 批量下载.缓 ...

  5. Android进阶之路 - 批量下载、缓存图片

    在日常项目开发中,关于图片批量下载,数据缓存的相关功能比比皆是,这次也是去年在项目中需要在本地缓存商品数据,所以用到了批量下载的功能,特此记录 ~ 关联篇 Android进阶之路 - 批量下载.缓存图 ...

  6. Android 垂直同步和三重缓冲

    帧率是每秒钟内游戏能够渲染的画面数量,取决于电脑的硬件配置.屏幕刷新率是屏幕在每秒钟能刷新的次数,单位是赫兹(Hz),这取决于显示器的硬件配置.假设CPU/GPU 性能高在你的游戏中能够获得超过200 ...

  7. VSYNC+三重缓存机制+Choreographer

    从 Android 4.1 开始,谷歌在黄油计划中,引入了了三个核心元素,即 VSYNC.Triple Buffer 和 Choreographer. 在一个典型的显示系统中,一般包括CPU.GPU. ...

  8. Android开源框架——图片加载与缓存库 Picasso

    介绍 Picasso是由Square开发的一款图片库,具有强大的下载与缓存功能,可以对图片进行处理.它简化了来自外部图片的处理过程,尤其是远程图片. 开源地址:https://github.com/s ...

  9. android分享图片功能实现原理,Android:简单实现并理解图片三级缓存

    学习Android网络开发的过程中,势必会经历很多痛苦的过程,其中一个大坑就是图片缓存,当然现在有很多现成的库非常方便,常常几行代码就可以实现想要的功能,但不懂其中的原理是不行的,所以对于刚开始学习网 ...

最新文章

  1. Android调用WebService系列之对象构建传递
  2. linux系统的初化始配置
  3. ASP.NET中MVC默认模板的项目结构
  4. 体二极管的原理及应用
  5. php点击价格_按价格从高到低排序和从低到高排序_可点击切换,WooCommerce 教程:[解决] 排序,航运成本 – 从低到高...
  6. bugly中批量隐藏版本
  7. Ubuntu 携手初创企业用代码开拓物联网
  8. php opendir 不能用,PHP opendir() 函数
  9. 运维审计是什么意思?有什么作用?用什么软件好?
  10. android怎样开启root权限管理,【经验】安卓手机怎么开启Root权限?
  11. linux系统的wps办公软件,wps32位/64位linux版办公软件-WPS Office 2019 For Linux下载V11.1.0.10161官方版-西西软件下载...
  12. sql语言之模糊查询
  13. 外网使用easyconnect链接校园网
  14. 新东方老师谈如何学英语
  15. 如何从电压范围75V-3500V中选购合适的GDT-陶瓷气体放电管-优恩
  16. Bootstrap Table 中文文档(完整翻译版)
  17. Mac 电脑wify 没有ip地址
  18. Xilinx Kintex-7 XC7K325T-2FFG676I嵌入式核心板简介
  19. 详解诊断数据库ODX-C
  20. 正则表达式:只能输入以字母开头,数字或者字母结尾,并由数字、字母、下划线组成的字符串,且字符串中必须包含下划线!

热门文章

  1. 金山现任CEO张宏江将退休 西山居CEO继任
  2. 坚定、信心和进取是成功的基石
  3. 我使用过的Linux命令之usleep - 延迟以微秒为单位的时间
  4. 通用搜索引擎和垂直搜索引擎的区别
  5. Kermit文件传输协议
  6. C++第三方日志库Pantheios
  7. 推送系统从0到1(八):个性化精准推送的实现
  8. oracle子查询练习题与答案解析 笔记 小白练习!(内有福利)
  9. 对抗机器学习——FGSM经典论文 EXPLAINING AND HARNESSING ADVERSARIAL EXAMPLES
  10. 【附源码】计算机毕业设计SSM人力资源管理系统