Preface

Android中,Client测量和计算布局,SurfaceFlienger(server)用来渲染绘制界面,client和server的是通过匿名共享内存(SharedClient)通信。

每个应用和SurfaceFlienger之间都会创建一个SharedClient,一个SharedClient最多可以创建31个SharedBufferStack,每个surface对应一个SharedBufferStack,也就是一个Window。也就意味着,每个应用最多可以创建31个窗口。


Android 4.1 之后,AndroidOS 团队对Android Display进行了不断地进化和改变。引入了三个核心元素:Vsync,Triple Butter,Choreographer。

首先来理解一下,图形界面的绘制,大概是有CPU准备数据,然后通过驱动层把数据交给GPU来进行绘制。图形API不允许CPU和GPU直接通信,所以就有了图形驱动(Graphics Driver)来进行联系。Graphics Driver维护了一个序列(Display List),CPU不断把需要显示的数据放进去,GPU不断取出来进行显示。

其中Choreographer起调度的作用。统一绘制图像到Vsync的某个时间点。

Choreographer在收到Vsync信号时,调用用户设置的回调函数。函数的先后顺序如下:

CALLBACK_INPUT:与输入事件有关
CALLBACK_ANIMATION:与动画有关
CALLBACK_TRAVERSAL:与UI绘制有关

Vsync是什么呢?首先来说一下什么是FPS,FPS就是Frame Per Second(每秒的帧数)的缩写,我们知道,FPS>=60时,我们就不会觉得动画卡顿。当FPS=60时是个什么概念呢?1000/60≈16.6,也就是说在大概16ms中,我们要进行一次屏幕的刷新绘制。Vsync是垂直同步的缩写。这里我们可以简单的理解成,这就是一个时间中断。例如,每16ms会有一个Vsync信号,那么系统在每次拿到Vsync信号时刷新屏幕,我们就不会觉得卡顿了。

但实现起来还是有点困难的。

多重缓冲是什么技术呢?我们先来说双重缓冲。在Linux上,通常使用FrameBuffer来做显示输出。双重缓冲会创建一个FrontBuffer和一个BackBuffer,顾名思义,FrontBuffer是当前显示的页面,BackBuffer是下一个要显示的画面。然后滚动电梯式显示数据。为什么呢?这样好在哪里呢?首先他并不是不卡了,他还是会卡。但是如果是单重缓冲,页面可能会有这种情况:A面数据需要显示,然后是B面数据显示,B面数据显示需要耗费一定时间,但是这个时间里,C面数据也请求了展示,我们可能会看到,在展示C面数据的时候,还有B面数据的残影…

下面分情况来具体说明一下(Vsync每16秒一次)。

1.没有使用Vsync的情况

可以看出,在第一个16ms之内,一切正常。然而在第二个16ms之内,几乎是在时间段的最后CPU才计算出了数据,交给了Graphics Driver,导致GPU也是在第二段的末尾时间才进行了绘制,整个动作延后到了第三段内。从而影响了下一个画面的绘制。这时会出现Jank(闪烁,可以理解为卡顿或者停顿)。那么在第二个16ms前半段的时间CPU和GPU干什么了?哦,他们可能忙别的事情了。这就是卡顿出现的原因和情况。CPU和GPU很随意,爱什么时候刷新什么时候刷新,很随意。

2.有Vsync的情况

如果,按照之前的前提来说,Vsync每16ms一次,那么在每次发出Vsync命令时,CPU都会进行刷新的操作。也就是在每个16ms的第一时间,CPU就会想赢Vsync的命令,来进行数据刷新的动作。CPU和GPU的刷新时间,和Display的FPS是一致的。因为只有到发出Vsync命令的时候,CPU和GPU才会进行刷新或显示的动作。图中是正常情况。那么不正常情况是怎么个情况?我们先来说一下双重缓冲,然后再说。

3.双重缓冲

逻辑就是和之前一样。多重缓冲页面在Back Buffer,然后根据需求来显示不同数据。但是会有什么问题呢(这就是2中提到的问题)?

首先我们看Display行,A页面需要了两个时间单位,为什么?因为B Buffer在处理的时候太耗时了。然后导致了,在第一个Vsync发出的时候,还在GPU还在绘制B Buffer。那么,刚好,第一个Vsync发出之后很短的时间,A页面展示完了,B Buffer的也在一开始的时候就不进行计算了。那么接下来的时间呢?屏幕还是展示着B Buffer,这时候就会造成Jank现象。他不会动,因为他在等下一个Vsync过来的时候,才会显示下一个数据。

那么,如图,在A Buffer过来的时候,展示B页面的数据。这个时候!重复了上一个情况,也是太耗时了,然后又覆盖了下一个Vysnc发
出的时间,再次造成卡顿!依次类推,会造成多次卡顿。这个时候就有了三重缓冲的概念。

4.三重缓冲

首先看图。我们看到,B Buffer依旧很耗时,同样覆盖了第一个Vsync发出的时间点。但是,在第一个Vsync发出的时候,C Buffer站了出来,说,我来展示这个页面,你去缓冲A后面需要缓冲的页面吧!然后会发生什么?然后就是出现了一个Jank…,但是这个Jank只在这一个时间单位出现,是可以忽略不计的。因为之后的逻辑都是顺畅的了。依次类推,除了A和B 两个图层在交替显示,还有个“第三者”在不断帮他们两个可能需要展示的数据进行缓冲。但是注意了:

只有在需要时,才会进行三重缓冲。正常情况下,只使用二级缓冲!

另外,缓冲区不是越多越好。上图,C页面在第四个时间段才展示出来,就是因为中间多了一个Buffer(C Buffer)来进行缓冲。

但是,虽然谷歌给了你这么牛逼的前提逻辑,实际开发中你写的APP还是会卡,为什么呢?原因大概有两点:

1.界面太复杂。

2.主线程(UI线程)太忙。他可能还在处理用户交互或者其他事情。

Android Vsync 原理浅析的更多相关文章

  1. Android IdleHandler 原理浅析

    IdleHandler:空闲监听器(就像我没事做了,在群里发了个表情,这时候其他人就知道我很闲了) 在每次next获取消息进行处理时,发现没有可以处理的消息(队列空,只有延时消息并且没到时间,同步阻塞 ...

  2. Android-Binder原理浅析

    Android-Binder原理浅析 学习自 <Android开发艺术探索> 写在前头 在上一章,我们简单的了解了一下Binder并且通过 AIDL完成了一个IPC的DEMO.你可能会好奇 ...

  3. HTTP长连接和短连接原理浅析

    原文出自:HTTP长连接和短连接原理浅析

  4. Android root 原理

    Android root 原理 0x00 关于root linux和类Unix系统的最初设计都是针对多用户的操作系统,对于用户权限的管理很非常严格的,而root用户(超级用户)就是整个系统的唯一管理员 ...

  5. NFC(6)NFC编程的几个重要类,NFC硬件启动android应用原理

    用于NFC编程的几个重要类 Tag NFC 标签 NfcAdapter Nfc 的适配类 NdefMessage 描述NDEF格式的信息 NdefRecord 描述NDEF信息的一个信息段,类似tab ...

  6. Javascript自执行匿名函数(function() { })()的原理浅析

    匿名函数就是没有函数名的函数.这篇文章主要介绍了Javascript自执行匿名函数(function() { })()的原理浅析的相关资料,需要的朋友可以参考下 函数是JavaScript中最灵活的一 ...

  7. android的原理,为什么不需要手动关闭程序

    转自android的原理,为什么不需要手动关闭程序 不用在意剩余内存的大小,其实很多人都是把使用其他系统的习惯带过来来了. Andoird大多应用没有退出的设计其实是有道理的,这和系统对进程的调度机制 ...

  8. Android源码浅析(六)——SecureCRT远程连接Linux,配置端点和字节码

    Android源码浅析(六)--SecureCRT远程连接Linux,配置端点和字节码 需要编译源码的同学,一般都是win+虚拟机吧,但是再虚拟机里体验并不是很好,所有市面上有很多的软件能够做到在wi ...

  9. Android源码浅析(五)——关于定制系统,如何给你的Android应用系统签名

    Android源码浅析(五)--关于定制系统,如何给你的Android应用系统签名 今天来点简单的我相信很多定制系统的同学都会有一些特定功能的需求,比如 修改系统时间 静默安装 执行某shell命令 ...

随机推荐

  1. idea自己用得到的命令

    1.注释 Ctrl + / 单行注释 . 取消注释 Ctrl + Shift + / 多行注释 .取消注释 2.查找 Ctrl + N 通过输入类名打开类(标准说法是查找类文件) Ctrl + Shi ...

  2. ajax 提交添加元素内容

    JS <script type="text/javascript"> $('.Phone_Interview_Comments').click(function () ...

  3. .NET平台常用框架

    分布式缓存框架: Microsoft Velocity:微软自家分布式缓存服务框架. Memcahed:一套分布式的高速缓存系统,目前被许多网站使用以提升网站的访问速度. Redis:是一个高性能的K ...

  4. dex内存提取

    转 http://blog.csdn.net/asmcvc/article/details/18216531 智能手机的普及将移动互联网的发展推到了一个让所有人都为之兴奋的高度,我想即使是以商业眼光见 ...

  5. zepto中的touch库与fastclick

    1. touch库实现了什么和引入背景 click事件在移动端上会有 300ms 的延迟,同时因为需要 长按 , 双触击 等富交互,所以我们通常都会引入类似 zepto 这样的库.zepto 中tou ...

  6. 用Filter作用户授权的例子

    public class LoginFilter implements Filter { private String permitUrls[] = null; private String goto ...

  7. 【详解】ThreadPoolExecutor源码阅读(二)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) AQS在W ...

  8. PHP self this parent

    {一}PHP中this,self,parent的区别之一this篇 面向对象编程(OOP,Object OrientedProgramming)现已经成为编程人员的一项基本技能.利用OOP的思想进行P ...

  9. Python面试题目--汇总

    原文链接-https://github.com/taizilongxu/interview_python Python语言特性 1 Python的函数参数传递 2 Python中的元类(metacla ...

  10. redis使用watch秒杀抢购思路

    1.使用watch,采用乐观锁 2.不使用悲观锁,因为等待时间非常长,响应慢 3.不使用队列,因为并发量会让队列内存瞬间升高 测试代码: import java.util.concurrent.Exe ...