一、使用
1.定义两个类:BlockDetector.java、LogMonitor.java。
2.在Application中执行初始化方法。
二、原理
1.主线程所有的操作都是通过handler来执行的,所以只要监测每个msg执行的时间,就能定位出哪个方法造成卡顿。
2.在Loop.java的loop()方法中,每次执行msg.target.dispatchMessage(msg)前后都会分别打印以“>>>>> Dispatching”为前缀和“<<<<< Finished”为后缀的信息,只要通过setMessageLogging()替换Loop.java中的Printer类,就可以检测到处理每个msg的开始和结束时间。
public class BlockDetector {
public static void init() {
Looper.getMainLooper().setMessageLogging(new Printer() {
//分发和处理消息开始前的log
private static final String START = ">>>>> Dispatching";
//分发和处理消息结束后的log
private static final String END = "<<<<< Finished";
@Override
public void println(String x) {
if (x.startsWith(START)) {
//开始计时
BlockMonitor.getInstance().startMonitor();
}
if (x.startsWith(END)) {
//结束计时
BlockMonitor.getInstance().removeMonitor();
}
}
});
}
}
public class BlockMonitor {
private static final String TAG = "=====BlockMonitor=====";
private static BlockMonitor sInstance = new BlockMonitor();
private Handler mIoHandler;
//方法耗时的卡口,500毫秒
private static final long TIME_BLOCK = 500L;
//存放一个msg周期的卡顿堆栈信息,防止重复打印
private Set<String> mBlockStackTrace;
private BlockMonitor() {
HandlerThread logThread = new HandlerThread("BlockMonitor");
logThread.start();
mIoHandler = new Handler(logThread.getLooper());
mBlockStackTrace = Collections.synchronizedSet(new HashSet<String>());
}
private Runnable mLogRunnable = new Runnable() {
@Override
public void run() {
//继续检测
startMonitor();
//打印出执行的耗时方法的栈消息
StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
StringBuilder sb = new StringBuilder();
for (StackTraceElement s : stackTrace) {
sb.append(s.toString());
sb.append("\n");
}
String s = sb.toString();
if (!mBlockStackTrace.contains(s)) {
mBlockStackTrace.add(s);
Log.e(TAG, s);
}
}
};
public static BlockMonitor getInstance() {
return sInstance;
}
/**
* 开始计时
*/
public void startMonitor() {
mIoHandler.postDelayed(mLogRunnable, TIME_BLOCK);
}
/**
* 停止计时
*/
public void removeMonitor() {
mIoHandler.removeCallbacks(mLogRunnable);
mBlockStackTrace.clear();
}
}
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
BlockDetector.init();
}
}