移动APP性能评测-流畅度评测

为了提升流畅度,Google对Android系统进行了大量的优化,包括使用GPU进行硬件加速、引入VSYNC,把Dalvik换成art等。重点讲解FPS测量流畅度的不足,对测量流畅度的方法进行改进,然后介绍如何定位流畅度问题,最后总结流畅度优化方法,以及在开发过程中如何避免流畅度降低问题。简单来说就是如何更加准确测量流畅度如何定位流畅度问题如何优化流畅度问题

流畅度评测方法介绍:

1.FPS:每秒的帧数;测量流畅度的时候有时候FPS很低,但是App看起来很流畅;
2.SM(Smoothness,SM)流畅度;
3.SF(Skipped frames):丢帧;
FPS测量流畅度过程中的两个问题:
1.为什么有时候FPS很低,但是我们却不觉得APP卡顿?
2.App停止操作之后,FPS还是一直在变化,这样的情况是否会影响FPS的准确度,
系统获取FPS的原理:手机屏幕显示的内容是通过Android系统的SurfaceFlinger类把当前系统里所有进程需要显示的信息合成一帧,然后提交到屏幕进行显示,FPS就是1s内SurfaceFlinger提交到屏幕的帧数;
问题一答案:有时候FPS很低,我们却感觉不到卡顿,是因为如果我们的屏幕根本没有绘制需求,即屏幕的显示画面是静止的,这时候FPS就是0,并不是FPS越低就越卡顿;对于界面一直不停刷新的应用如视频,可以使用FPS来评价其流畅度;
问题二答案:APP停止操作之后FPS还一直变化,是因为屏幕每一帧的合成都是针对手机里所有的进程,那么即使你的app停止了绘制,手机里其他进程可能还在绘制,比如状态栏的各种消息,这回导致FPS继续变化;
所以FPS评价流畅度很多时候不准确。
在Android系统显示原理简介中,我们介绍了Android系统的显示过程,可以发现在引入VSYNC信号之后,丢帧是给人卡顿感觉的元凶,所以丢帧也可以用来测量流畅度;实际上,我们很多APP中,很少需要不断绘制的场景,很多的时候是静态的。会出现这样的情况,虽然1s中VSYNC的60个loop中不是每个都是在做绘制工作,FPS比较低并不能代表这个时候不流畅,所以FPS为1并不能代表当前APP UI界面不流畅,因此1秒内VSYNC这个loop能运行多少次更加能说明当前APP的流程度;所以丢帧和SM比FPS更能代表当前APP的流畅度。
丢帧:应该在16ms完成的工作因各种原因没有做完,占了下n个16ms的时间,相当于丢了n帧。
SM:和丢帧相对,在VSYNC机制中1s内有60个loop,因为某几次工作超过了16ms(丢帧),这样loop就无法运行60次(理论最大值);流畅度越低说明当前程序越卡顿;

如何得到流畅度(SM)

Android系统从4.1(API 16)开始加入Choreographer这个类来控制同步处理输入(Input)、动画(Animation)、绘制(Draw)三个UI操作。VSync信号由SurfaceFlinger实现并定时发送。Choreographer.FrameDisplayEventReceiver收到信号后,调用onVsync方法组织消息发送到主线程处理。Choreographer主要功能是当收到VSync信号时,去调用使用通过postCallBack设置的回调函数,我们可以在使用postFrameCallBack接口注册一个回调,每当下一帧到来时都会通知我们,我们就可以直接在回到Choreographer.FrameCallback中的doFrame方法时通知我们,我们简单的去计数就可以,然后按秒做统计,就可以知道每秒执行loop的次数;关于Choreographer更详细内容可参考Android Choreographer 源码分析;所以这个loop在1秒内运行的次数便是当前APP绘制的最高能力,也就是APP的卡顿程度;在一次loop时,如果执行时间超过16.6ms,那么多于16.6ms的时间除以16.6ms,即当前APP的丢帧情况;所以以上两个指标都可以表示当前APP的卡顿程度;但是因为SM是一个连续过程,SF非连续,所以建议采用SM作为客观指标来描述APP卡顿程度;
SM能够客观衡量Android程度卡的程度
1.根据Google文档,以及Android源码,以及SM原理理论都可以证实SM数值可以客观表示APP ui卡的程度;理论基础:Android系统显示原理简介、Android Choreographer 源码分析,简单来说就是SurfaceFlinger每16毫秒会发生VSYNC信号,Choreographer.FrameDisplayEventReceiver收到信号后,调用onVsync方法组织消息发送到主线程处理,最终我们可以在Choreographer.FrameCallback中的doFrame进行计数,知道每一秒loop多少次,loop次数当前APP绘制的最高能力,这样就可以知道当前APP的流畅度

private final class FrameDisplayEventReceiver extends DisplayEventReceiver        
implements Runnable {    
  public FrameDisplayEventReceiver(Looper looper) {    
    super(looper);
  }
  @Override 
  public void onVsync(long timestampNanos, int  builtInDisplayId, int frame) {
  ...     
  mTimestampNanos = timestampNanos;        
  mFrame = frame;        
  Message msg = Message.obtain(mHandler, this);        
  msg.setAsynchronous(true);
  //发送消息,在looper下一次循环时执行run方法;
  mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);    
  }    
  @Override    
  public void run() {        
    mHavePendingVsync = false;
    /*渲染下一帧,并顺序执行callBack队列里面的callback,我们可以在使用postFrameCallBack接口注册一个回调,
     每当下一帧到来时都会到Choreographer.FrameCallback中的doFrame方法时通知我们,
    这样我们就可以知道一定时间内渲染了多少帧,也可以知道一秒内loop执行了多少次*/
    doFrame(mTimestampNanos, mFrame);    
  }
}

2.根据原理制定一些测试,观察SM数据,也可以客观表示某个Android APP卡的程度;
3.SM计算公式:SM = (60* totalSeconds - totalSkippedFrames) / totalSeconds;
丢帧(SF)能够客观描述Android程序卡的程度
1.根据Google文档,以及Android源码,以及丢帧原理都可以证实SF数值同样可以客观表示APP ui卡的程度;
2.根据原理制定一些测试,观察丢帧数据,也可以客观表示某个Android APP卡的程度;
3.但是由于这项数据时不连续的,而是离散的,所以可以作为辅助数据来评价流畅度;
当把APP静止在某个界面时流畅度很高,FPS比较低,无丢帧情况下流畅度和丢帧两个数据更加接近人对卡顿的主观感受;在APP有界面比不停变化时(如视频类应用)FPS一定程度上可以客观量化卡顿的主观感受;无变化则无法反应;无论界面是否有变化,流畅度和丢帧都可以客观量化卡顿的主观感受;建议在量化人对卡顿的主观感受主要以流畅度(SM)为主,丢帧(SF)、FPS作为辅助指标;

流畅度优化流程

1.首先通过SM对流畅度进行测试评估;
2.然后从最简单的UI层入手,优化APP的UI来提升流畅度;相关内容可参考Keeping your app responsive以及Improving Layout Performance等;
3.通过lint静态扫描发现代码中存在性能的问题;然后进行优化;相关内容可以参考使用 Lint 改进您的代码
4.最后进一步深入分析APP逻辑层和IO层存在的问题;代码逻辑分析部分,Android提供了两个很好用的工具:Systrace、Inspect trace logs with Traceview,后续会介绍检测应用中的UI卡顿方法;

相关背景知识:

Android消息机制、Android系统显示原理、Choreographer 源码分析

参考资料:

《移动APP性能评测与优化》--第3章 怎样才能如丝般顺滑—流畅度评测
Android 显示原理简介
Android Choreographer 源码分析
腾讯Bugly的专栏--那些年我们用过的显示性能指标

你可能感兴趣的:(移动APP性能评测-流畅度评测)