Android App卡顿分析,以及使用Choreographer进行帧率统计监测

1、背景:

卡顿是最影响App用户体验的原因之一。卡顿造成的原因多种多样,简单列举一下 
  
1、布局层级过多,设置无用的背景色,布局中添加了多种不必要的背景色,导致view绘制的时候多次绘制,引起卡顿 
2、布局太复杂,嵌套过多,例如RelativeLayout 相比LinearLayout,可以有效减少布局层级,层级太复杂,会影响view的measure时间,进而造成卡顿。 
3、内存使用不当,主线程做了大量计算或者IO操作等,这样就不举例说明了。

2、性能问题常用检测方法

检测app绘制性能的方法多种多样:

如针对对于布局层级过多,可以使用开发者选项-->调用GPU过度绘制 方式查看。

针对布局复杂,可以用Hierarchy Viewer

也可以使用腾讯提供的性能检测工具:GT(GitHub地址:https://github.com/FanGuangcheng/GT)

 然而,这所有的检测方法都是开发阶段进行的,当我们的app投放到市场之后,我们不知道用户那边使用的真实场景是怎样的。

我们开发、测试进行的性能检测,都是针对我们的开发机器,没法真实模拟用户场景,比如用户多种多样的机型、内存大小、app使用状态、SD卡使用状态等等。 
因此我们需要一种线上的监测机制,实时统计用户的卡顿数据,获得用户使用的第一手资料,并有针对性的对某些功能页面进行优化,更好的提升用户体验。



3、android绘制原理

* Android 16ms原理*:Android系统每隔16ms会发出VSYNC信号重绘我们的界面(Activity).为什么是16ms, 因为Android设定的刷新率是60FPS(Frame Per Second), 也就是每秒60帧的刷新率, 约合16ms刷新一次. 
如下图所示: 
16ms

如图中所示,每隔16ms,系统都会发出VSYNC信号,如果这时候我们的画面(view)准备好了,我们的view绘制就会很流畅。如果我们在这个16ms间隔内,没有准备好画面(view),那么这一次绘制,就不会展示在屏幕上,就相当于少绘制了一帧,画面就会出现卡顿,断断续续。 如下图所示

卡顿的原因

4、Choreographer 监测掉帧原理

在Choreographer中有个回调接口,FrameCallback。

public interface FrameCallback 

public void doFrame(long frameTimeNanos); 
}
 
doFrame 的注释如下:* Called when a new display frame is being rendered. 
就是说,当新的一帧被绘制的时候被调用。 
因此我们利用这个特性,可以统计两帧绘制的时间间隔。 
主要流程如下: 
* 1、实现Choreographer.FrameCallback接口
* 2、在doFrame中统计两帧绘制的时间,代码与注释如下: 
@Override 
public void doFrame(long frameTimeNanos) { 
if (mLastFrameNanoTime != 0) {//mLastFrameNanoTime 上一次绘制的时间 
long frameInterval = frameTimeNanos - mLastFrameNanoTime;//计算两帧的时间间隔 
//如果时间间隔大于最小时间间隔,3*16ms,小于最大的时间间隔,60*16ms,就认为是掉帧,累加统计该时间 
//此处解释一下原因: 因为正常情况下,两帧的间隔都是在16ms以内 ,如果我们统计到的两帧间隔时间大于三倍的普通绘制时间,我们就认为是出现了卡顿,之所以设置最大时间间隔,是为了有时候页面不刷新绘制的时候,不做统计处理 
if (frameInterval > MIN_FRAME_TIME && frameInterval < MAX_FRAME_TIME) { 
long time = 0; 
if (mSkipRecordMap.containsKey(mActivityName)) { 
time = mSkipRecordMap.get(mActivityName); 

mSkipRecordMap.put(mActivityName, time + frameInterval);//统计时间 


mLastFrameNanoTime = frameTimeNanos; 
Choreographer.getInstance().postFrameCallback(this); 
Runtime.getRuntime().maxMemory(); 
}

  • 3、启动监测 
    public void start() { 
    Choreographer.getInstance().postFrameCallback(FrameSkipMonitor.getInstance()); 
    }

  • 4、上报处理 
    在doFrame选中,我们已经统计到了想要的数据,然后我们将time的值除以16600000(因为我们统计的时间是纳秒),就是掉帧的数字。

猜你喜欢

转载自blog.csdn.net/suyimin2010/article/details/81406827