当前位置:   article > 正文

Android UI卡顿检测(二)——基于WatchDog原理的方案(线上方案)_android looper.getmainlooper().thread.stacktrace

android looper.getmainlooper().thread.stacktrace

卡顿介绍


我们前文已经在 Android UI卡顿检测(一)——基于Handler机制的实现方案(线上方案) 中做了介绍。

想要了解的,可以点击上面链接来回顾。

基于WatchDog原理的方案及代码实现


由于在Android 5.0及以上系统中,默认启动了SELinux机制,所以我们的App在线上场景中,不能获得ANR的系统日志。但是ANR又是我们App稳定性指标的一部分,所以有此方案,配合前文 Android UI卡顿检测(一)——基于Handler机制的实现方案(线上方案) 来保障App在线上运行中的体验。

原理

我们想要监控的是UI线程的卡顿,如果卡顿超过了5s,系统就会ANR,那么我们可以设置一个阈值,比如4s,超过阈值的卡顿,我们把UI线程的运行堆栈上传到我们的分析后台。

那么,如何监控UI线程的长时间卡顿呢?

参考系统的WatchDog原理,我们启动一个卡顿检测线程,该线程定期的向UI线程发送一条延迟消息,执行一个标志位加1的操作,如果规定时间内,标志位没有变化,则表示产生了卡顿。如果发生了变化,则代表没有长时间卡顿,我们重新执行延迟消息即可。

代码实现

public class WatchDog {
    private final static String TAG = "budaye";
    //一个标志
    private static final int TICK_INIT_VALUE = 0;
    private volatile int mTick = TICK_INIT_VALUE;
    //任务执行间隔
    public final int DELAY_TIME = 4000;
    //UI线程Handler对象
    private Handler mHandler = new Handler(Looper.getMainLooper());
    //性能监控线程
    private HandlerThread mWatchDogThread = new HandlerThread("WatchDogThread");
    //性能监控线程Handler对象
    private Handler mWatchDogHandler;

    //定期执行的任务
    private Runnable mDogRunnable = new Runnable() {
        @Override
        public void run() {
            if (null == mHandler) {
                Log.e(TAG, "handler is null");
                return;
            }
            mHandler.post(new Runnable() {
                @Override
                public void run() {//UI线程中执行
                    mTick++;
                }
            });
            try {
                //线程休眠时间为检测任务的时间间隔
                Thread.sleep(DELAY_TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //当mTick没有自增时,表示产生了卡顿,这时打印UI线程的堆栈
            if (TICK_INIT_VALUE == mTick) {
                StringBuilder sb = new StringBuilder();
                StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
                for (StackTraceElement s : stackTrace) {
                    sb.append(s.toString() + "\n");
                }
                Log.d(TAG, sb.toString());
            } else {
                mTick = TICK_INIT_VALUE;
            }
            mWatchDogHandler.postDelayed(mDogRunnable, DELAY_TIME);
        }
    };

    /**
     * 卡顿监控工作start方法
     */
    public void startWork(){
        mWatchDogThread.start();
        mWatchDogHandler = new Handler(mWatchDogThread.getLooper());
        mWatchDogHandler.postDelayed(mDogRunnable, DELAY_TIME);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

我们通过调用startWork方法即可开启卡顿监控,原理和实现步骤,注释已经非常详尽了,这里不做重复解析了。

总结


  1. 在Android 5.0及以上系统中,默认启动了SELinux机制,所以我们的App在线上场景中,不能获得ANR的系统日志。
  2. 我们启动一个卡顿检测线程,该线程定期的向UI线程发送一条延迟消息,执行一个标志位加1的操作,如果规定时间内,标志位没有变化,则表示产生了卡顿。如果发生了变化,则代表没有长时间卡顿,我们重新执行延迟消息即可。
  3. 该方案可以根据自己的需求设置时间间隔。
  4. 该方案并不能完全检测到所有的设定条件内的卡顿问题,但可以配合前文的方案来实现交叉覆盖,基本可以满足我们的需求。

PS:性能优化专栏:《Android性能》持续更新中……

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/143198
推荐阅读