赞
踩
我们前文已经在 Android UI卡顿检测(一)——基于Handler机制的实现方案(线上方案) 中做了介绍。
想要了解的,可以点击上面链接来回顾。
由于在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);
}
}
我们通过调用startWork方法即可开启卡顿监控,原理和实现步骤,注释已经非常详尽了,这里不做重复解析了。
PS:性能优化专栏:《Android性能》持续更新中……
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。