原理
开启一个异步线程,每过一段时间(比如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
}
}
}