public final void run() {
long loopTime = 2500L;
long eventTime = (System.nanoTime() / 100000L) + loopTime;
while (true) {
calcutionsTakingVaryingAmountOfTime(); // takes 200 millisecs or less
long eventWait = eventTime - (System.nanoTime() / 100000L);
Thread.sleep(eventWait / 10L);
listener.onEvent();
eventTime = eventTime + loopTime;
}
}
需要精确计时的是对 listener.onEvent()
的调用。
在上面的示例中,时间变量 loopTime
、eventTime
和 eventWait
以毫秒的十分之一为单位测量时间。同样以毫秒的十分之一为单位测量当前时间的表达式 (System.nanoTime() / 100000L)
。
我非常确定 calcutionsTakingVaryingAmountOfTime()
总是少于 200 毫秒,并且对 listener.onEvent()
的调用只需要几毫秒。因此,如果将 loopTime
设置为 2500L
,那么我的事件应该每 250 毫秒发生一次。
我已经在我的代码中添加了仪器(未显示),以便将 Thread.sleep()
的唤醒时间延迟打印到 Log.d()
中。也就是说,我计算的是
long latency = (System.nanoTime() / 100000L) - eventTime
在从Thread.sleep()
返回后立即将其打印到Log.d()
中。
当我在模拟器中运行时,我发现延迟
(除以10后得到毫秒数)在连续通过循环时通常会在1到50毫秒之间跳动,偶尔会高达半秒钟。在实际设备上运行时,情况好了很多,但仍然有点不稳定(而且即使在模拟器上的表现也让我想知道是否会在用户设备上出现这种情况)。
为了尝试稳定我的事件并控制延迟,我尝试了几种其他方法:
用调用
this.wait(eventWait / 10L)
代替了Thread.sleep(eventWait / 10L)
的方式(我知道这是一个完全不恰当的wait()使用方法)在进入循环之前,我操纵了线程优先级,像在android库中所做的那样,调用
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
但是这些都没有改善延迟。
唯一一个稳定事件,并将延迟降低到少于2到3毫秒,并且很少有抽搐的方法是通过替换Thread.sleep()
调用为轮询循环:
while ((System.nanoTime() / 100000L) < eventTime)
;
一方面,我觉得像一个醉汉一样浪费机器周期很尴尬。另一方面,我开始认为没有比在轮询循环中消耗机器周期更好的方法,我应该在这里烧掉机器周期以减少延迟并满足我的规格要求。当然,当我的应用程序进入后台时,我会暂停线程,因此这个轮询循环可以工作。但真是太浪费了。
如果有任何想法,将不胜感激。
Thread.sleep()
破坏了我的应用程序,因为我也有像你描述的那样大的延迟。但是,你如何使用Timer
模拟Thread.sleep
?你已经找到更好的解决方案了吗? - Luis A. Florit