极简耗时方法检测器

原理

开启一个异步线程,每过一段时间(比如100ms)就去获取主线程的栈帧
如果当前栈帧和上一个栈帧一样,就说明主线程阻塞了,就打印当前的栈帧

注意:需要过滤掉系统的阻塞方法

代码

package com.daigou.sg.helper

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.util.Log

/**
 * Author:Yutianran on 2019-08-01 16:57
 */
object BlockDetectUtil {

    private val TIME_BLOCK = 100L//阈值,可以自己配置

    private val whiteList = mutableListOf<String>().apply {
        add("android.os.MessageQueue.nativePollOnce")
        add("ThreadedRenderer.nSyncAndDrawFrame")
    }

    private val ioHandler: Handler by lazy {
        val handlerThread = HandlerThread("BlockDetectUtil")
        handlerThread.start()
        return@lazy Handler(handlerThread.looper)
    }

    @JvmStatic
    fun init() {
        ioHandler.post(ioRunnable)
    }

    private val ioRunnable = object : Runnable {

        var last = ""

        override fun run() {
            val stackTraceString = getMainThreadStackTrace()
            if (checkBlock(stackTraceString)) {
                Log.e("BlockDetectUtil", "当前方法耗时超过${TIME_BLOCK}ms:\n $stackTraceString")
            }
            last = stackTraceString
            ioHandler.postDelayed(this, TIME_BLOCK)
        }

        private fun getMainThreadStackTrace(): String {
            val sb = StringBuilder()
            val stackTrace = Looper.getMainLooper().thread.stackTrace
            for (s in stackTrace) {
                sb.append(s.toString() + "\n")
            }
            return sb.toString()
        }

        private fun checkBlock(stackTraceString: String): Boolean {
            whiteList.forEach {
                if (stackTraceString.contains(it)) {
                    return false
                }
            }
            if (last == stackTraceString) {
                return true
            }
            return false
        }

    }

}

效果

推荐阅读更多精彩内容