Android 性能优化篇

性能优化之 Skipped Frames

2023-08-07  本文已影响0人  Tsm_2020

在开发过程中发现页面卡顿的时就能在Logcat 中发现如下的日志

Skipped 30 frames! The application may be doing too much work on its main thread.

这个日志就是在提醒我们需要做性能优化,关于这个掉帧的具体由来可以查看我的另一篇博客 Choreographer 编舞者的艺术(https://www.jianshu.com/p/3650dc59976a) 中查看,这篇文章我们主要来说一下针对这种情况如何排查,

消息队列机制

image.png

上面画的这张图片阐述了一种丢帧的可能,就是在屏障消息添加之前,我们向MessageQueue中添加了一些比较耗时的操作,导致消息屏障执行时机太晚,
在这个方向上我们就需要知道Looper 到底在处理哪一个消息,这个消息耗时了多久,其实这些东西在Looper的设计初衷时就给我们预留了后门,下面贴一下相关代码

image.png

public static void loop() {
      final Looper me = myLooper();
       // 省略代码....
      for (;;) {
          Message msg = queue.next(); // might block
          if (msg == null) {
              // No message indicates that the message queue is quitting.
              return;
          }
          final Printer logging = me.mLogging;
          if (logging != null) {
              logging.println(">>>>> Dispatching to " + msg.target + " " +
                      msg.callback + ": " + msg.what);
          }
          ////省略代码...
          if (logging != null) {
              logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
          }
      }
  }

在looper 的loop 方法中他会轮序去处理消息,得到消息后,他会判断一下是否有Priner 来判断输出消息开始处理和结束处理的日志信息,我们可以通过这些东西来判断msg 处理是否合理

Choreographer 队列机制


        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

刷新处理的时机也与 input 事件 动画等息息相关,如果在 Choreographer CallbackQueue 队列数组中的任意一个环节出现了执行时间过程,可能都会导致丢帧
从网上看过一些大神的文章,他们的做法是使用 反射的方式,在 doframe时向 CallbackQueue 数组中添加添加一个头部消息,这样数组中第一个消息处理的时机就是当前链表的开始时间,下一个头部既是下一组事件的开始时间,同时也是上一组事件的结束时间,来判断 这 4 个环节哪一个出现了问题,
第一个数据就代表的是 input 事件, 例如 event 等
第二个代表的是动画事件 复杂的动画,或者同一时间执行的动画比较多,可能导致丢帧
第三个代表的是插入动画事件
第四个代表的是整个绘制流程 从 performMeasure 一直到 onDraw 方法的耗时 ,这个节点经常出现问题

知道了在哪一个环节出现了问题,剩下的问题就比较好做了,
我遇到过的 就是 在onDraw 中 频繁的处理和销毁对象导致频繁的gc ,gc 的过程中为了保证指针的准确性 jvm 会 Stop The Word, 让整个系统都停一下,等待他处理完在继续工作,这就会导致丢帧

还遇到过布局层次不合理, 重复设置无用背景导致过度绘制 ,

也使用过canvas.clipPaht 来约束绘制边界来预防过度绘制等问题,

也遇到过在onCreate中确实需要初始化好多的控件,导致加载过慢,也可以使用 StubView 在请求结果后再inflate 控件,减少 在同一时间的工作量来达到优化的部分内容

也遇到过在打开activity 在onCreate中初始化复杂的动画,导致第一帧帧既要做动画,又要做一些测量 布局 绘制等工作导致的,在同一帧执行的任务比较多而导致的少量丢帧

应该还有其他的可以优化的点,但是我暂时就想到了这么多,如果你认为还有其他的,请联系我一起探讨,共同进步!

上一篇下一篇

猜你喜欢

热点阅读