开发者

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,

  1. Is your task blocking (maybe on some UI thing)?
  2. 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.
  3. Is your TimerTask properly synchronized with the UI event loop (i.e., is it updating the label in the correct runLater() 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 is invokeLater() or maybe invokeAndWait(), depending on what you're trying to accomplish.

Edited after code posted:

A couple of useful and relevant resources are here.

  1. OK, I'd still say to instrument your code with some logging or println calls to output timestamps when it runs.
  2. Not sure why the schedule() call is inside its own Runnable... 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 the Timer and call schedule() 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.
  3. I still think you may want to do something like:
  4. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜