涉及到相关概念
手机屏幕刷新率:手机硬件每秒刷新屏幕的次数,单位HZ。一般是一个固定值,例如60HZ。
系统合成帧率(FPS):手机屏幕显示的内容是通过Android系统的SurfaceFlinger类把当前系统里所有进程需要显示的信息合成一帧,然后提交到屏幕进行显示,FPS就是1s内SurfaceFlinger提交到屏幕的帧数;
流畅度(SM):数据形式与 FPS 类似,可以很好的弥补 FPS 无法准确刻画非连续绘制的应用显示性能的缺陷;1s内VSync这个Loop运行了多少次更加能说明当前App的流畅程度。
VSync是Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就广泛使用的技术,可以简单的把它认为是一种定时中断。而在Android 4.1(JB)中已经开始引入VSync机制。它的作用是使GPU的渲染频率与显示器的刷新频率(一般为固定值)同步从而避免出现画面撕裂的现象。
【垂直同步】
Vertical Synchronization,屏幕从图形芯片获取每帧的数据,然后逐行进行绘制。理想状况下,你期望显示屏在绘制完一帧之后,图形芯片整好能提供新帧的数据。图像撕裂的状况就发生在图形芯片在图像绘制到一半的时候,就载入了新一帧的数据,以致你最终得到的数据帧是半个帧的新数据和半个帧的老数据。而垂直同步,顾名思义就是用来同步的。它告知GPU在载入新帧之前,要等待屏幕绘制完成前一帧
应用跳帧次数、幅度(Aggregate frame stats):除了对系统平台有较高的要求以外,其采集方式最为简单(系统自带功能);
帧率:GPU在一秒内绘制的帧数
丢帧(Skipped frames):Android系统每隔16ms发出VSYNC信号,触发GPU对UI进行渲染,如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候由于还没有准备好,就无法进行更新任何内容,那么用户在32ms内看到的会是同一帧画面(卡顿现象),即丢帧现象。
撕裂:因为屏幕的刷新过程是自上而下、自左向右的,如果帧率>刷新率,当屏幕还没有刷新n-1帧的数据时,就开始生成第n帧的数据了,从上到下,覆盖第n-1帧。如果此时刷新屏幕,就会出现图像的上半部分是第n帧的,下半部分是第n帧的现象。CPU/GPU一直都在渲染。
------------------------------------------------------------------------------------------------------
FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。FPS是测量用于保存、显示动态视频的信息数量。每秒钟帧数愈多,所显示的动作就会愈流畅。
´一般来说,Android设备的屏幕刷新率为60帧/s,要保持画面流畅不卡顿,要求每一帧的时间不超过1000/60=16.6ms,这就是16ms的黄金准则,如果中间的某些帧的渲染时间超过16ms,就会导致这段时间的画面发生了跳帧,因此原本流畅的画面变发生了卡顿。实际上在很多Android的App中,很少有需要不断地去绘制的场景,很多时候页面都是静态的。也就是会出现这样的状况,虽然1s中VSync的60个Loop不是每个都在做绘制的工作,FPS会比较低,但并不代表这个时候程序不流畅(如我将App放着不动,实测FPS为1)。所以FPS较低并不能代表当前App在UI上界面不流畅,而1s内VSync这个Loop运行了多少次更加能说明当前App的流畅程度。
想要让大脑觉得动作是连续的,至少是每秒10-12帧的速度,而想达到流畅的效果,至少需要每秒24帧。这也是为什么电影片源通常都是24帧的原因,好奇的同学点击>>知乎高知看看大神的解答。不过60帧每秒的流畅度是最佳的,我们的目标就是让程序的流畅度能接近60帧每秒,当然超过60帧速的话大部分人还是会受不了的。
APP需要尽可能的超过24帧/秒,接近60帧/秒的速度,并且在使用的过程中保持这个速率,试想一下你吃着火锅看着电影,突然图像发生了跳跃或者画面撕裂,那种感觉就像米饭里吃到了沙子一样极度不爽,因此这意味着我们的程序需要在16.67ms
内处理一幅画面内的所有事,并保持住这个状态
获取FPS的方式:
方法一:
通过 [设置]->[开发者选项]->[GPU呈现模式分析] ->[在屏幕上显示为条形图] 进行直观的取样。
优点:可直接在手机上操作,方便直观
缺点:这个方式获取到的渲染时间只是UI主线程上的绘制行为。“GPU呈现模式分析”的数据只能说明个现象,比如上面提到的数据,能说明在实际运行中会有短暂的长时间绘制问题。但造成问题的具体原因并没有说明。
而且“GPU呈现模式分析”显示的是最后128帧的数据,但丢帧也有可能是两帧之间存在长时间的操作而造成的。
方法二、
1、adb命令
1)打开手机:开发者选项—>profile GPU rendering —> in adb shell dumpsys gfxinfo
2) 操作要测试的apk
3) cmd窗口输入命令: adb shell dumpsys gfxinfo packageName
4) 得到一个矩阵数据,计算矩阵中帧率大于16的点所占比例,即为卡顿比
含义:
Draw: 表示在Java中创建显示列表部分中,说白了就是执行每一个View的onDraw方法,创建或者更新每一个View的DisplayList对象的时间。
Process:表示消耗在Android的2D渲染引擎执行显示列表所花的时间,view越多,时间就越长。
Execute:表示把一帧数据发送到屏幕上排版显示实际花费的时间。消耗在排列每个发送过来的帧的顺序的时间.或者说是CPU告诉GPU渲染一帧的时间,这是一个阻塞调用,因为CPU会一直等待GPU发出接到命令的回复。所以这个时间,一般都很短。
Draw + Process + Execute = 完整显示一帧 ,这个时间要小于16ms才能保存每秒60帧
将数据复制到excel中,然后将数据生成“堆积柱形图”。
参考:https://blog.csdn.net/v1003499773/article/details/80415062
方法三、通过系统层级SurfaceFlinger获取
原文链接:https://blog.csdn.net/xiaomaoxiao336368/article/details/83547318
Draw(蓝)表示View.onDraw()方法的耗时,这部分主要是建立DisplayList对象用的,这些对象将会被转化成OpenGL命令,GPU只能读懂OpenGL命令。如果这个地方耗时比较大,说明视图比较复杂。蓝色区域代表的时间,是创建DisplayList对象的时间。
Prepared(紫)5.1以后将UI Thread线程所做的事分成了2个线程来做:UI Thread和Render Thread。新加的Render Thread线程会将Draw过程生成的DisplayList对象转化成为OpenGL的命令,然后发送给GPU,这个时候UI Thread可以空闲下来处理下一个frame的数据。如果传送的资源过多的话这个地方耗时就比较大。紫色区域代表的时间就是UI Thread传送数据给Render Thread所用的时间。
Process(红)红色区域代表创建OpenGL命令的时间,表示渲染引擎执行显示列表所花的时间,view越多,时间就越长。
Execute(黄)黄色区域代表发送OpenGL命令给GPU所用的时间,表示把一帧数据发送到屏幕上排版显示实际花费的时间。其实是实际显示帧数据的后台缓存区与前台缓冲区交换后并将前台缓冲区的内容显示到屏幕上的时间。所以这个时间,一般都很短。
-------------------------------------------------------------
获取SM的方式