android 动画在某个界面卡顿_Android 流畅度检测原理简析

程序流畅度是很重要的一个指标,重要是因为用户可以直观体验到,为啥别人家的程序都是如丝般顺滑( •̀ ω •́ )✧( •̀ ω •́ )✧( •̀ ω •́ )✧,今天就来聊聊系统是如何判断程序卡顿。不知道你曾注意过这样一条系统日志Choreographer(1434): Skipped 35 frames! The application may be doing too much work ...
摘要由CSDN通过智能技术生成

程序流畅度是很重要的一个指标,重要是因为用户可以直观体验到,为啥别人家的程序都是如丝般顺滑( •̀ ω •́ )✧( •̀ ω •́ )✧( •̀ ω •́ )✧,今天就来聊聊系统是如何判断程序卡顿。

不知道你曾注意过这样一条系统日志

Choreographer(1434): Skipped 35 frames!  The application may be doing too much work on its main thread.

当出现这条信息,意味着我们程序执行过程中出现了卡顿,需要进一步优化。

一、黄油计划(Project Butter)

android在不同的版本都会优化“UI的流畅性”问题,但是直到在android 4.1版本中做了有效的优化,这就是Project Butter,所谓的黄油计划,android工程师真会起名字。

Project Butter加入了三个核心元素:VSYNC、Triple Buffer和Choreographer。其中VSYNC是理解Project Buffer的核心。VSYNC是Vertical Synchronization的缩写 也就是“垂直同步”

1.1.没有VSYNC前

c712222728f9a4589f1214cf86b9a7ba.png
  • 时间从0开始,进入第一个16ms:Display显示第0帧,CPU处理完第一帧后,GPU紧接其后处理继续第一帧。三者互不干扰,一切正常。
  • 时间进入第二个16ms:因为早在上一个16ms时间内,第1帧已经由CPU,GPU处理完毕。故Display可以直接显示第1帧。显示没有问题。但在本16ms期间,CPU和GPU却并未及时去绘制第2帧数据(注意前面的空白区),而是在本周期快结束时,CPU/GPU才去处理第2帧数据。
  • 时间进入第3个16ms,此时Display应该显示第2帧数据,但由于CPU和GPU还没有处理完第2帧数据,故Display只能继续显示第一帧的数据,结果使得第1帧多画了一次(对应时间段上标注了一个Jank)。
  • 通过上述分析可知,此处发生Jank的关键问题在于,为何第1个16ms段内,CPU/GPU没有及时处理第2帧数据?原因很简单,CPU可能是在忙别的事情(比如某个应用通过sleep固定时间来实现动画的逐帧显示),不知道该到处理UI绘制的时间了。可CPU一旦想起来要去处理第2帧数据,时间又错过了

1.2.引入了VSYNC

70efbc56b45d32ad2d000c54d4eafb45.png

Vsync提高了图形性能,为了确保整个体验的帧速率一致,从Android 4.1开始将vsync定时扩展到Android框架处理的所有绘图和动画。一切都与16毫秒的vsync“心跳”相协调——应用程序渲染、触摸事件、屏幕合成和显示刷新——因此帧不会超前或落后。

二、应用卡顿检测

Android系统每隔16.6ms发出VSYNC信号,来通知界面进行输入、动画、绘制等动作,每一次同步的周期为16.6ms,代表一帧的刷新频率,理论上来说两次回调的时间周期应该在16.6ms,如果超过了16.6ms我们则认为发生了卡顿,利用两次回调间的时间周期来判断是否发生卡顿 这个方案的原理主要是通过Choreographer类设置它的FrameCallback函数,当每一帧被渲染时会触发回调FrameCallback, FrameCallback回调void doFrame (long frameTimeNanos)函数。一次界面渲染会回调doFrame方法,如果两次doFrame之间的间隔大于16.6ms说明发生了卡顿

2.1.Choreographer类

监控应用的流畅度一般都是通过Choreographer类的postFrameCallback方法注册一个VSYNC回调事件

public static void start(final Builder builder) {        Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {            long lastFrameTimeNanos = 0;            long currentFrameTimeNanos = 0;            @Override            public void doFrame(long frameTimeNanos) {                if (lastFrameTimeNanos == 0) {                    lastFrameTimeNanos = frameTimeNanos;                    LogMonitor.getInstance().setFrequency(builder.frame * 17 / 2);                    if (builder.targetPackageName != null) {                        LogMonitor.getInstance().setTargetPackageName(builder.targetPackageName);                    }                    LogMonitor.getInstance().setDumpListener(builder.onDumpListener);                }                currentFrameTimeNanos = frameTimeNanos;                skipFr
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值