适用场景 debug 本地测试
文章目录
- 代码类 MainThreadMonitor.java
- 使用方式 Application的attachBaseContext
- log输出示例
代码类 MainThreadMonitor.java
public class MainThreadMonitor {
private static final String TAG = "MainThreadMonitor";
private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
public static void startMonitorMainThread(long threshold) {
executorService.scheduleAtFixedRate(() -> {
checkMainThreadState(threshold);
}, 0, threshold, TimeUnit.MILLISECONDS);
}
private static void checkMainThreadState(long threshold) {
AtomicBoolean exec = new AtomicBoolean(false);
long startTime = System.currentTimeMillis();
Handler mainHandler = new Handler(Looper.getMainLooper());
// 预期主线程执行runnable的时候会把 exec置为true
mainHandler.post(() -> exec.set(true));
executorService.schedule(() -> {
// 阈值之后发现 exec 还没有置为true,说明主线程阻塞了
if (!exec.get()) {
printMainThreadStackTrace(startTime);
}
}, threshold, TimeUnit.MILLISECONDS);
}
private static void printMainThreadStackTrace(long startTime) {
StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
long consumeTime = System.currentTimeMillis() - startTime;
Log.e(TAG, String.format("start block:(%s) ms ====================== ", consumeTime));
for (StackTraceElement s : stackTrace) {
Log.d(TAG, "block: " + s);
}
}
}
使用方式 Application的attachBaseContext
class App : Application() {
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MainThreadMonitor.startMonitorMainThread(500)
}
}
log输出示例
这里需要解释一下 start block 这行的含义,我们看到后面有一个 501ms的耗时,这里并不意味着该方法/函数执行的时间是501ms,而是表述这500ms之内都在此方法中执行,很有可能下一个500ms还是这个堆栈信息,因此 方法实际执行时间 >= 500ms