简单易用的Android主线程耗时检测类 MainThreadMonitor

适用场景 debug 本地测试

文章目录

  • [代码类 MainThreadMonitor.java](#代码类 MainThreadMonitor.java)
  • [使用方式 Application的attachBaseContext](#使用方式 Application的attachBaseContext)
  • log输出示例

代码类 MainThreadMonitor.java

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

kotlin 复制代码
class App : Application() {

    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        MainThreadMonitor.startMonitorMainThread(500)
    }

}

log输出示例

这里需要解释一下 start block 这行的含义,我们看到后面有一个 501ms的耗时,这里并不意味 着该方法/函数执行的时间是501ms,而是表述这500ms之内都在此方法中执行,很有可能下一个500ms还是这个堆栈信息,因此 方法实际执行时间 >= 500ms

相关推荐
zh_xuan4 小时前
Android Looper源码阅读
android
用户02738518402614 小时前
[Android]RecycleView的item用法
android
前行的小黑炭15 小时前
Android :为APK注入“脂肪”,论Android垃圾代码在安全加固中的作用
android·kotlin
帅得不敢出门16 小时前
Docker安装Ubuntu搭建Android SDK编译环境
android·ubuntu·docker
tangweiguo0305198716 小时前
Android Kotlin 动态注册 Broadcast 的完整封装方案
android·kotlin
fatiaozhang952716 小时前
浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
android·网络·adb·电脑·电视盒子·刷机固件·机顶盒刷机
前行的小黑炭17 小时前
Android 不同构建模式下使用不同类的例子:如何在debug模式和release模式,让其使用不同的类呢?
android·kotlin·gradle
andyguo18 小时前
AI模型测评平台工程化实战十二讲(第一讲:从手工测试到系统化的觉醒)
android
2501_9159214318 小时前
小团队如何高效完成 uni-app iOS 上架,从分工到工具组合的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
幂简集成18 小时前
通义灵码 AI 程序员低代码 API 课程实战教程
android·人工智能·深度学习·神经网络·低代码·rxjava