一、 AndroidPerformanceMonitor
:
原理是基于Handler-Message
机制,
监控主线程每一个Message的执行,
在每一个Message的分发执行前后,进行信息处理;
(不足:
一般没有阻塞的情况下,
每一个Message的执行时间是非常短暂的,
达不到ANR的级别;
而且InputEvent在queue.next中block,不会继续执行dispatchMessage,
而是从native回调给InputEventReceiver.dispatchInputEvent处理分发,
所以BlockCanary也就无法监控到这类ANR)
二、 ANR-WatchDog:
不管主线程是怎么执行的,
只管最后的结果,
我sleep一个周期之后,就要看我_tick值有没有被修改, 没被修改就是ANR
!
AndroidPerformanceMonitor适合全程监控卡顿,
ANR-WatchDog适合补充ANR监控;
两者可以相辅相成,结合使用!
三、 Choreographer.FrameCallback
public class BlockDetectByChoreographer {
public static void start() {
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
long lastFrameTimeNanos = 0;
long currentFrameTimeNanos = 0;
@Override
public void doFrame(long frameTimeNanos) {
if(lastFrameTimeNanos == 0){
lastFrameTimeNanos == frameTimeNanos;
}
currentFrameTimeNanos = frameTimeNanos;
long diffMs = TimeUnit.MILLISECONDS.convert(currentFrameTimeNanos-lastFrameTimeNanos, TimeUnit.NANOSECONDS);
if (diffMs > 16.6f) {
long droppedCount = (int)diffMs / 16.6;
}
if (LogMonitor.getInstance().isMonitor()) {
LogMonitor.getInstance().removeMonitor();
}
LogMonitor.getInstance().startMonitor();
Choreographer.getInstance().postFrameCallback(this);
}
});
}
}
优点
:不仅可用来从app层面来监控卡顿,同时可以实时计算帧率和掉帧数,实时监测App页面的帧率数据,一旦发现帧率过低,可自动保存现场堆栈信息。
缺点
:需另开子线程获取堆栈信息,会消耗少量系统资源。
- StackTrace 的收集
StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
for (StackTraceElement s : stackTrace) {
sb.append(s.toString() + "\n");
}
Log.e("TAG", sb.toString());
}
- LogMonitor
本质上,是通过一个HandlerThread 里边去抓取 Thread的 trace。
public class LogMonitor {
private static LogMonitor sInstance = new LogMonitor();
private HandlerThread mLogThread = new HandlerThread("log");
private Handler mIoHandler;
private static final long TIME_BLOCK = 1000L;
private LogMonitor() {
mLogThread.start();
mIoHandler = new Handler(mLogThread.getLooper());
}
private static Runnable mLogRunnable = new Runnable() {
@Override
public void run() {
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
for (StackTraceElement s : stackTrace) {
sb.append(s.toString() + "\n");
}
Log.e("TAG", sb.toString());
}
};
public static LogMonitor getInstance() {
return sInstance;
}
public boolean isMonitor() {
return mIoHandler.hasCallbacks(mLogRunnable);
}
public void startMonitor() {
mIoHandler.postDelayed(mLogRunnable, TIME_BLOCK);
}
public void removeMonitor() {
mIoHandler.removeCallbacks(mLogRunnable);
}
}
参考文章
1.Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)