美文网首页
[037]Choreographer Skipped含义再探

[037]Choreographer Skipped含义再探

作者: 王小二的技术栈 | 来源:发表于2020-03-12 13:15 被阅读0次

    前言

    [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的方案。

    相关文章

      网友评论

          本文标题:[037]Choreographer Skipped含义再探

          本文链接:https://www.haomeiwen.com/subject/qszejhtx.html