我产生定时事件在一个(非UI)的循环线程在Android应用程序,我需要这些事件发生在precise间隔时间,(precise在这里是指不改变任何超过+/- 5的毫秒)。 +/- 10的毫秒(当然+/- 20的毫秒)的任何错误可被用户感知。在这个循环的顶部余做取可变的时间量的一些其他的计算,但在循环的底部,我需要的事件发生在一个$ P $对计算时间
I am generating timing events in a loop in a (non-UI) thread in an Android application, and I need those events to occur at precise intervals in time, (precise here means not varying any more than +/- 5 millisecs). Any errors of +/-10 millisecs (and certainly +/- 20 millisecs) can be perceived by the user. At the top of this loop I do some other calculations that take a variable amount of time, but at the bottom of the loop, I need the event to occur at a pre-calculated time.
一个higly简化版本(没有异常处理)的一个尝试,我非UI线程如下:
A higly simplified version (without exception handling) of one attempt at my non-UI thread is below:
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()
,需要加以precisely时机。
It is the call to listener.onEvent()
that needs to be precisely timed.
在上面的例子中,时间变量 LOOPTIME
, eventTime
和 eventWait
测量时间在毫秒的十分之一。这位前pressions (System.nanoTime()/ 100000L)
测量电流的时间也同样在一毫秒的十分之一。
In the example above, the timing variables loopTime
, eventTime
, and eventWait
measure time in tenths of a millisec. The expressions (System.nanoTime() / 100000L)
measuring current time are likewise in tenths of a millisec.
我绝对肯定, calcutionsTakingVaryingAmountOfTime()
的总是的花费不到200的毫秒,并调用监听器。的onEvent()
只是少数的毫秒。因此,作为它的立场,与 LOOPTIME
设置为 2500L
,我的事件应该发生的每一个250的毫秒。
I am absolutely certain that calcutionsTakingVaryingAmountOfTime()
always takes less than 200 millisecs, and the call to listener.onEvent()
is just a few millisecs. So as it stands, with loopTime
set to 2500L
, my events ought to occur every 250 millisecs.
我已经intstrumented我的code(未显示)打印到 Log.d()
在视频下载的等待时间( )
唤醒时间。也就是说,我计算
I have intstrumented my code (not shown) to print to Log.d()
the latency in the Thread.sleep()
wake up time. That is, I calculate
long latency = (System.nanoTime() / 100000L) - eventTime
从返回视频下载()
,并打印到 Log.d后立即()
。
当我运行这在模拟器中,我找到的是,延迟
通常跳1至50的毫秒(除以10,得到的结果进入的毫秒后)在相继通过循环通过,偶尔值高达一个半秒钟。当一个实际的设备上运行,事情都相当好一点,但还是有一点摇晃(甚至还在,模拟器的行为使我怀疑这会发生在用户的设备)。
When I run this in the emulator, what I find is that latency
(after dividing by 10 to get the result into millisecs) is normally jumping between 1 and 50 millisecs in successive passes through the loop, with occasional values as high as a half a second. When run on an actual device, things are quite a bit better, but still a little wobbly (and even still, the emulator behavior makes me wonder if this is going to happen on users' devices).
要设法稳住我的事件和控制延迟,我尝试过其他几种方法:
To try to steady my event and control the latency, I tried several other approaches:
在更换了视频下载(eventWait / 10L)
调用,通过调用 this.wait(eventWait / 10L)
(完全不恰当地使用wait()的,我所知道的)
In replaced the Thread.sleep(eventWait / 10L)
call, with a call to this.wait(eventWait / 10L)
(a completely inappropriate use of wait(), I know)
我操纵进入循环,调用之前线程优先级 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
就像是在Android的库所做的一切。
I manipulated the thread priorities prior to entering the loop, calling Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
like is done all over the android libraries
但没有改善在所有在这些等待时间。
But there was no improvement at all in the latency with these.
的一种方法是steadys事件,并缩短了延迟的小于2或3的毫秒的,很少打嗝是替换视频下载()
通过轮询循环调用:
The one approach that steadys the event, and reduces the latency to less than 2 or 3 millisecs, and rarely hiccups is to replace the Thread.sleep()
call by a polling loop:
while ((System.nanoTime() / 100000L) < eventTime)
;
在一方面,我觉得自己像在自由喝醉的水手尴尬的消费机器周期。在另一方面,我开始觉得没有更好的办法,我就烧了机器周期的轮询循环,减少我的延迟,并符合我的标准。当然,在我的应用程序去的背景下,我停下我的线,所以这个查询循环工作。但是,什么是浪费。
On the one hand, I feel embarrassed spending machine cycles like a drunken sailor on liberty. On the other hand, I am beginning to think there is no better way, and I should burn the machine cycles in the polling loop to reduce my latency, and meet my specification. Of course, when my app goes to the background, I pause my thread, so this polling loop works. But what a waste.
任何想法将大大AP preciated。
Any ideas would be greatly appreciated.
我使用的是与处理程序
类似用途延迟的消息。它可以是有点矫枉过正。在你的情况我会看看到定时器
类。
I'm using delayed messages with Handler
for similar purpose. It can be little overkill. In you case I would take a look to Timer
class.
mTimer = new Timer();
mTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Log.v("TEST", " tick");
}
}, 0, 250);
这给了我的等待时间+ -2时的毫秒模拟器。
This gives me latency +-2 millisecs at emulator.