我在Android应用程序的(非UI)线程中循环生成计时事件,我需要这些事件以精确的时间间隔发生,(这里的精确意味着不会超过+/- 5)的毫秒)。用户可以感知到+/- 10毫秒(当然+/- 20毫秒)的任何误差。在这个循环的顶部,我做了一些其他计算需要花费不同的时间,但是在循环的底部,我需要在预先计算的时间发生事件。
我的非UI线程的一次尝试的高度简化版本(无异常处理)如下:
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毫秒发生一次。
我已经修改了我的代码(未显示),以便在Log.d()
唤醒时间内打印到Thread.sleep()
延迟。也就是说,我计算
long latency = (System.nanoTime() / 100000L) - eventTime
从Thread.sleep()
返回后立即,并将其打印到Log.d()
。
当我在模拟器中运行它时,我发现latency
(在除以10后得到的结果为毫秒)通常在连续的循环中跳过1到50毫秒,偶尔价值高达半秒。当在实际设备上运行时,事情会好一些,但仍然有点不稳定(甚至,模拟器行为让我想知道这是否会发生在用户的设备上)。
为了尝试稳定我的事件并控制延迟,我尝试了其他几种方法:
取代Thread.sleep(eventWait / 10L)
来电,拨打this.wait(eventWait / 10L)
(完全不恰当地使用wait(),我知道)
我在进入循环之前操纵了线程优先级,调用Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
就像在整个android库中完成一样
但是这些延迟并没有任何改善。
一种可以稳定事件并将延迟减少到小于2或3毫秒并且很少打嗝的方法是用轮询循环替换Thread.sleep()
调用:
while ((System.nanoTime() / 100000L) < eventTime)
;
一方面,我感到尴尬的是像醉酒的水手那样花机器自行车。另一方面,我开始认为没有更好的方法,我应该在轮询循环中烧掉机器周期以减少延迟,并符合我的规范。当然,当我的应用程序转到后台时,我会暂停我的线程,因此这个轮询循环可以工作。但是多么浪费。
非常感谢任何想法。
答案 0 :(得分:2)
我正在使用Handler
的延迟消息用于类似目的。它可能有点矫枉过正。在你的情况下,我会看看Timer
类。
mTimer = new Timer();
mTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Log.v("TEST", " tick");
}
}, 0, 250);
这使我在模拟器上的延迟+ -2毫秒。