专栏首页王小二的Android站[037]Choreographer Skipped含义再探

[037]Choreographer Skipped含义再探

前言

[036]Choreographer Skipped真正含义中,我介绍了一种可以产生Choreographer Skipped的情况。就是在onVsync被调用之前,往主线程post的一个Message。那还有没有其他方式可以产生这个Choreographer Skipped呢?

一、仔细看看代码

@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
    ...
    //onVsync方法将会在Vsync信号接收之后被回调
    //mTimestampNanos就是这次Vsync信号接收的时间
    mTimestampNanos = timestampNanos;
    mFrame = frame;
    //往主线程的Looper中投放一个Asynchronous的Message,callback为this
    //这个Message被处理的时候就会调用下面run-doFrame的方法
    Message msg = Message.obtain(mHandler, this);
    msg.setAsynchronous(true);
    mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

请注意onVsync参数中timestampNanos,这个值代表什么呢,其实代表的是Vsync信号到达App的时间,Vsync信号在通过socket通信发给App时候,会带上这个时间戳timestampNanos,这个过程其实是不会受主线程影响的。

在Vsync信号到来之后,onVsync方法没有被立刻调用,也可以产生Choreographer Skipped

二、写个Demo验证一下

public class Main2Activity extends AppCompatActivity implements View.OnClickListener {

    private TextView mTxtView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        mTxtView = findViewById(R.id.txt_view);
        mTxtView.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        mTxtView.setText("请求Vsync信号");//会触发scheduleTraversals,所以16ms以内会接受到Vsync信号
        try {
            Thread.sleep(1000);//这样子onVsync会推迟1000ms,才能被调用
        } catch (Exception e) {

        }
    }
}

注意我这里采用的是TextView,因为TextView点击没有UI刷新,所以不会触发scheduleTraversals,我在onClick中主动调用mTxtView.setText,会触发scheduleTraversals,所以App会在16ms以内会接受到Vsync信号,请注意16ms以内,时间不固定。

Vsync信号到来的时间点就是onVsync的形参timestampNanos。

然后mTxtView.setText完了之后再sleep 1000ms,处理完onClick代码。主线程会去处理onVsync的方法,由于Vsync信号早就到了,所以就算此时onVsync投放的Asynchronous的Message被立刻处理,但是已经晚了,所以还是会出现Choreographer Skipped。

D KobeWang2: onClick : start
D KobeWang2: onClick : end
I Choreographer: Skipped 60 frames!  The application may be doing too much work on its main thread.

三、总结

其实有很多Demo可以产生Choreographer Skipped,但是不管你怎么写,肯定是下面两种场景之一。

3.1 场景一

[036]Choreographer Skipped真正含义里介绍的Demo,虽然Vsync信号到了,onVsync被及时调用,但是主线程中有未开始处理的耗时Message,推迟了doFrame的执行时间。

场景一

3.2 场景二

本文介绍的Demo,Vsync信号早早到了,但是由于主线程的耗时操作,onVsync无法被及时调用

场景二

3.3 更正

更正一下我在[036]Choreographer Skipped真正含义说的话

Choreographer Skipped真正反映的是onVsync和doFrame两个方法调用的时间间隔

修正为

Choreographer Skipped真正反映的是Vsync信号到达App的时间和doFrame方法调用的时间间隔

场景一和场景二,只不过是通过两种方式增大了这个时间间隔而已。

3.4 onVsync被调用

我无数次的提到onVsync被调用,那到底onVsync是怎么被调用的,其实主线程的Looper.loop中一次循环会先处理native层监听的vsync信号和Input事件,处理一次java层的Message,就是类似这样子的伪代码。

public void loop() {
    for(;;) {
        //处理native层的任务,处理完所有vsync信号,input事件。
        //如果发现Vsync信号已经抵达APP,就会通过JNI回调onVsync方法
        doNativeTasks();
        //处理java层的Message,一次处理只能处理一个Message
        doJavaTasks();
    }
}

从主线程的Looper角度分析场景一和场景二的流程图如下: 充分展示了Vsync黄色块和doFrame紫色块之间的时间间隔是怎么被增大的。

尾巴

还记得神雕侠侣中找到情花毒解药的天竺神僧嘛,他先让自己中毒,才找到解药。所以我们在解决一些疑难BUG的时候,需要学会如何制造BUG,才能了解BUG产生的原理,才能找到解决BUG的方案。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [041][译]f2fs.txt

    一直想深入研究一下f2fs文件系统,但是网上的资料不是特别友好,我发现源码下有一个f2fs.txt,看了一下,但是英语比较差,看的效果不好。我决定花点时间一字一...

    王小二
  • [029]如何获取屏幕帧率

    在王小二图解Android【006】高帧率屏幕这期的视频中,我给大家揭秘今年所有安卓旗舰都会吹的高帧率屏幕,其实高帧率屏幕不需要应用开发人员去主动适配,只要应用...

    王小二
  • [035] onStop提前投放问题

    最近遇到一个奇葩的问题,应用X的Activity1中点击一个Button跳转到Activity2,手机A比手机B上快500ms左右,虽然手机A比手机B的配置高,...

    王小二
  • SSM 单体框架 - 前端开发:视频讲解

    前端代码发送给后台的日期数据使用 yyyy-MM-dd HH:mm:ss 的日期格式

    RendaZhang
  • Educational Codeforces Round 81 (Rated for Div. 2) B - Infinite Prefixes

    You are given string s of length nn consisting of 0-s and 1-s. You build an infi...

    glm233
  • 移动 Web 最佳实践(干货长文,建议收藏)

    https://juejin.im/post/5d759f706fb9a06afa32adec

    coder_koala
  • 移动 web 最佳实践(干货长文)

    https://juejin.im/post/5d759f706fb9a06afa32adec

    前端迷
  • 基于 Vue 和 TS 的 Web 移动端项目实战心得

    来源:https://juejin.im/post/5d759f706fb9a06afa32adec

    ConardLi
  • 狗哥肝了一下午的线程池,奉上~

    对线程还没有概念的小伙伴建议看看,哪里写错了,或写的不好的?给我提一些宝贵建议。感谢,今天进入线程的第六篇,线程池的学习。

    一个优秀的废人
  • Babel 及其工作原理

    Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览...

    Leophen

扫码关注云+社区

领取腾讯云代金券