TimerTask does not execute at predetermined interval
I'm writing a stopwatch application for BlackBerry (which is similar to the BlackBerry built-in StopWatch). There is a timer label displaying current time in the format MM:SS:T (minutes, seconds, tenth of second). The label is refresh each 100 millisecond with TimerTask.
The application works well and the time is display correctly, however, there are some moments the timer label is not updated at the predetermined interval (each 100 milliseconds). The timer label pauses (not counting) for a while and continues counting (while still displays the time correctly)
My thought is the TimerTask is not executed to update the timer label during this pause. Do you know why the app act this way, and how to fix it?
Below are the Thread to update the timer label:
public class ThreadUpdateTim开发者_如何学Ce extends Thread
{
private MyMainScreen myMainScreen;
private Timer updateTimerLabelTimer = new Timer();
public ThreadUpdateTime(MyMainScreen parent)
{
myMainScreen=parent;
}
public void run()
{
try {
updateTimerLabelTimer.schedule(new RecordTimer(myMainScreen), TIMER_DELAY, TIMER_INTERVAL);
} catch (Exception e) {
//put alert here
}
}
public void iStop()
{
updateTimerLabelTimer.cancel();
}
}
the timerTask:
public class RecordTimer extends TimerTask
{
private MyMainScreen myMainScreen;
public RecordTimer(MyMainScreen parent)
{
myMainScreen=parent;
}
public void run()
{
myMainScreen.iUpdateTimerLabel();
}
}
and the iUpdateTimerLabel method:
public void iUpdateTimerLabel()
{
//calculate : sign, sMin, sSec, sTenth
synchronized(Application.getEventLock())
{
lblSpotTime.setText(sign+sMin+":"+sSec+"."+sTenth+" ");
}
}
First is to measure it... log the timestamps when your timertask begins and ends, and see if it's really the TimerTask
that's really the problem. With that in hand, a couple of things that occur to me are,
- Is your task blocking (maybe on some UI thing)?
- Are there other tasks in the same
Timer
instance? I don't know if it's specified as such, but tasks probably all run on a single thread, so if another task is getting in the way, your tasks may not run at the exact specified interval. - Is your
TimerTask
properly synchronized with the UI event loop (i.e., is it updating the label in the correctrunLater()
or whatever method provided by the blackberry UI)? If you aren't doing this, the UI event loop may not notice that you've changed the label. I think on the Blackberry, the right thing isinvokeLater()
or maybeinvokeAndWait()
, depending on what you're trying to accomplish.
Edited after code posted:
A couple of useful and relevant resources are here.
- OK, I'd still say to instrument your code with some logging or println calls to output timestamps when it runs.
- Not sure why the
schedule()
call is inside its ownRunnable
... you don't need that, but maybe your application is doing that for some reason I can't see. If you think you're creating an explicit thread for the timer, you're not. You can probably just create theTimer
and callschedule()
from whatever application thread is setting this up.Timer
contains a captive thread that will do this work, and introducing Yet Another Thread is probably redundant and confusing. - I still think you may want to do something like:
- Another reminder to actually MEASURE what the timer is doing rather than relying on my speculation...
code inside the TimerTask
:
public void iUpdateTimerLabel()
{
//calculate : sign, sMin, sSec, sTenth
// synchronized(Application.getEventLock())
UiApplication.getUiApplication().invokeLater(
new Runnable() {
@Override
public void run() {
lblSpotTime.setText(sign+sMin+":"+sSec+"."+sTenth+" ");
}
});
}
Your synchronized
call may be enough to keep things from blowing up, but it's not really the preferred means. If the Timer
thread is dedicated to this single purpose, as it appears, you can probably replace invokeLater()
with invokeAndWait()
if you like.
Someone else may be able to elucidate the difference between just holding the UI lock and actually running on the UI thread, but my guess is that the latter forces an invalidate()
, and the former does not. This would explain why your label changes are only showing up sporadically.
精彩评论