一种寻找安卓应用绘制第一帧的方法

安卓中界面的呈现是通过窗口(window)来展现的,其中最主要的窗口是Activity,Activtiy主要以xml文件的形式来布局UI界面,最终会通过cpu和gpu来完成绘制工作,那么我们有没有办法来找到Activtiy第一帧绘制的时间点呢?

我们知道,安卓设备在绘制界面时,要求一帧需要在16毫秒以内完成,超过这个时间就可能造成丢帧的情况。这是因为系统底层每隔16毫秒会产生一个vsync信号,cpu接收到信号后,就开始计算一帧的绘制内容,然后通知gpu进行绘制。也就是说,如果我们找到第一个vsync信号发送的时刻,就可以知道应用程序第一帧的绘制时间点。

通过对源码和框架层api的查找,我们发了一个类:Choreographer,它的中文翻译为:舞蹈指导。。我们看下类的说明

/**
 * Coordinates the timing of animations, input and drawing.
 * 
 * The choreographer receives timing pulses (such as vertical synchronization)
 * from the display subsystem then schedules work to occur as part of rendering
 * the next display frame.
*/

意指:协调动画、输入、绘制的定时任务,行为是从显示子系统接收信号(垂直同步),然后分发下一帧的渲染工作。

顾名思义,它就是应用框架层接收垂直同步信号的类。也就是说,假如我们在应用刚启动,Activity还没有开始绘制的时候注册一个监听垂直同步信号的回调。我们就可以知道第一个垂直信号的接收点了。

我们进一步发现postFrameCallback方法可以向垂直同步信号处理队列添加一个处理任务。我们可以在其回调方法doFrame中对垂直同步信号进行拦截处理。。

完整操作为:

    Choreographer choreographer = Choreographer.getInstance();
    choreographer.postFrameCallback(this);
    
    
    @Override public void doFrame(long frameTimeNanos) {
    Log.e("wh", "start sleep");
    try {
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    Log.e("wh", "stop sleep");
  }

以上实例中,我们在入口类Application中处理的,这样正常情况下,我们会第一个接收到系统发出的垂直同步信号。接收到垂直同步信号后,将当前线程睡眠3000毫秒,可以预见的是:第一个Activtiy在执行完onResume方法后,界面内容会在至少3000毫秒以后才会展示出来。

世界测试中,我们发现也的确如此。

没有采用任何的反射、hook等手段,我们就简单的定位了应用程序第一帧绘制的时刻。

发布了46 篇原创文章 · 获赞 21 · 访问量 7070

猜你喜欢

转载自blog.csdn.net/lotty_wh/article/details/105171422