专项测试-流畅度测试之前的知识储备-Andorid中VSync机制的介绍

VSync 全称是Vertical Synchronization(垂直同步),在Android 4.1中引入Android 系统(同时引入的一个概念是Triple Buffering)。
学计算机的经常听到Buffer 的概念(生活中也碰到过很多,比如弹簧),起到的都是一个类似的作用。用来协调两个不同速度的东西工作
假设显示内容和绘制使用的是用一块内存,那可能会出现下面的问题。显示有截断的异常(图中的Tear Point #1和Tear Point #2)。为什么会这样呢?因为cpu/gpu 处理和屏幕展示的速度不一样但是却使用的是同一块内存。在这里插入图片描述

怎么解决呢?可以将cpu/gpu 处理和屏幕展示分开,cpu/gpu 在后台处理,处理完一帧的数据以后才交给屏幕展示(这样可能导致另外的问题是,如果cpu/gpu 处理很慢,那么屏幕可能会一直展示某一帧的数据,下面主要分析这个问题的处理)。

绘制过程中的两个概念。
  • 手机屏幕刷新率:手机硬件每秒刷新屏幕的次数,单位HZ。一般是一个固定值,例如60HZ。
  • FPS:画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。单位HZ。
    手机屏幕刷新率是固定的,FPS 则是一直变化的,怎么才能保证能够运行流畅呢?从几个例子来看吧。

先解释图片代表的意思:最下面黑线代表的是时间,黄色代表屏幕展示,绿色代表GPU 处理,蓝色代表CPU 处理。Jank 代表的是重复展示上一帧的异常。下面会从屏幕展示的每一帧开始分析

没有引入VSync 机制

在这里插入图片描述
上图是没有引入VSync 机制的处理流程。

Display 展示第0帧数据,这时cpu/gpu 会去处理第1帧的数据。
Display 展示第1帧数据(此时屏幕显示是正常的),这时cpu/gpu 可能处理其他任务导致很晚才去处理绘制。
因为cpu/gpu 没处理好第2帧的数据,所以Display 还是展示第1帧数据(此时屏幕显示是异常的),cpu/gpu 处理完第2帧没有处理完的数据然后继续处理第3帧的数据。

上图中一个很明显的问题是,只要一次cpu/gpu 处理出现异常就可能导致后面的一系列的处理出现异常。

引入VSync 机制

VSync 可以简单的认为是一种定时中断,系统在每次需要绘制的时候都会发送VSync Pulse 信号,cpu/gpu 收到信号后马上处理绘制。

正常情况

在4.1以后引入VSync 机制。
VSync机制的绘制
在FPS < 手机屏幕刷新率的情况下,一切运行完美。

Double Buffering 异常情况

VSync 机制下Double Buffering 时FPS > 手机屏幕刷新率的情况。
VSync机制出现double buffering

  • Display 展示第A 帧数据,cpu/gpu 收到VSync Pulse 信号马上处理B 帧的数据,但是由于计算太多,导致没有在一个VSync 间隔内处理完。
  • 由于第B 帧数据没有处理好,Display 继续展示第A 帧数据(此时屏幕显示是异常的)。由于系统中只存在一块内存给cpu/gpu 处理绘制,所以在这个VSync 间隔内cpu 不处理任何事。
  • Display 展示第B 帧数据,cpu/gpu 收到VSync Pulse 信号马上处理即将展示A 帧的数据,由于计算太多,导致没有在一个VSync 间隔内处理完。
  • 需要展示的A 帧数据没有处理好,Display 继续展示第B 帧数据(此时屏幕显示是异常的)。由于系统中只存在一块内存给cpu/gpu 处理绘制,所以在这个VSync 间隔内cpu 不处理任何事。

    上图中一个很明显的问题是,只要出现一次Jank 就会影响下一次的VSync(cpu 不能工作)。
Triple Buffering 异常情况

Triple Buffering 的引入。
VSync机制出现triple buffering

  • Display 展示第A 帧数据,cpu/gpu 收到VSync Pulse 信号马上处理B 帧的数据,但是由于计算太多,导致没有在一个VSync 间隔内处理完。
    由于第B 帧数据没有准备好,Display 继续展示第A 帧数据(此时屏幕显示是异常的)。此时虽然B 被gpu 在使用,但是cpu 可以处理Buffer C(因为有3个缓冲)。
  • Display 展示第B 帧数据,gpu 继续处理上一步骤的C,cpu 则处理A。
    后续过程出错的情况被降低了…
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Android,我们可以使用AspectJ这个AOP框架将测试代码放到切面。 首先,在项目的build.gradle文件添加如下配置: ``` buildscript { dependencies { classpath 'org.aspectj:aspectjtools:1.8.13' } } apply plugin: 'android-aspectjx' ``` 然后,在需要使用AOP的module的build.gradle文件添加如下配置: ``` dependencies { compile 'org.aspectj:aspectjrt:1.8.13' } ``` 接着,创建切面类,实现需要拦截的方法。例如,我们需要在应用启动时打印日志,可以这样实现: ``` @Aspect public class AppStartupAspect { private static final String TAG = "AppStartupAspect"; @Pointcut("execution(* android.app.Application.onCreate())") public void appCreatePointcut() { } @Before("appCreatePointcut()") public void onAppCreate() { Log.d(TAG, "Application onCreate"); } } ``` 在上面的代码,我们通过@Aspect注解标记这是一个切面类,然后定义了一个切点appCreatePointcut,它表示拦截所有Application的onCreate方法。最后,在@Before注解定义了在切点执行前执行的代码,即打印日志。 最后,在Application的onCreate方法添加如下代码,让AspectJ框架加载切面: ``` @Override public void onCreate() { super.onCreate(); AspectJHelper.init(this); } ``` 这样,当应用启动时,AspectJ框架会自动加载切面,执行@Before注解的代码,从而达到在应用启动时打印日志的目的。 需要注意的是,使用AspectJ需要开启Java8支持,可以在module的build.gradle文件添加如下配置: ``` android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } ``` 希望能对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值