这里用于总结一些在工作中发现的调试技巧。

Handler是否繁忙?

这一技巧来自于最近工作中,做子线程渲染时,发现有卡顿、手势操作延迟过大的情况,而渲染的子线程是一个HandlerThread,为了判断此线程是否有大量耗时操作,探索出一些技巧。

##判断HandlerThread是否繁忙##
可以通过对应的Handler执行一个post操作,在看其中执行的延迟,代码如下:

1
2
3
4
5
6
val handler = Handler(renderThread.looper)
val postAt = System.currentTimeMillis()
handler.post {
val delay = System.currentTimeMillis() - postAt
Log.d(TAG, "renderThread.delay=$delay")
}

在正常情况下,delay的值是很小的,大概率为0,但是,如果renderThread异常繁忙,则这个值会很大,说明等了很久来轮到一个需要立马执行的操作执行到,具体这个阈值怎么来定,要看你的实际场景,一般做ui渲染的话,超过17ms就可以认为是比较耗时了。
这个操作可以定时执行用于检测是否繁忙,也可以用于在怀疑的操作后添加此行为,判断是否是之前的操作耗时过长引起了操作延迟过大。

##如何找到导致繁忙的操作?##
上述操作,一般是用于常规检测和重点怀疑,如果要做“普筛”,则需要通过代理的方式。方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class DebugThread(val task: Runnable, val postDelayed: Long) :  Runnable {

private val pendingRunAt = System.currentTimeMillis() + postDelayed

override fun run() {
val now = System.currentTimeMillis()
task.run()
val cost = System.currentTimeMillis() - now
val delay = now - pendingRunAt
if (delay < 10 && cost > 160) {
Log.w(TAG, "Oops!!!")
}
}
}

需要将所有handler.posthandler.postDelayed中的Runnable换成上面的代理类,在代理类中观察是否有耗时操作,一般delay比较小,说明此操作前没有耗时操作导致当前操作延迟,而cost值比较大,说明会引起之后操作延迟过大,可以在打印出具体的delaycost值进行操作前后比较。
不过这种方式的缺点是不够灵活,需要将大量的,甚至是所有的post操作进行代理。

本文采用CC-BY-SA-3.0协议,转载请注明出处
Author: boybeak