TimerTask не выполняется с заданным интервалом - PullRequest
1 голос
/ 04 ноября 2010

Я пишу приложение секундомера для BlackBerry (которое похоже на встроенный в BlackBerry StopWatch). Имеется метка таймера, отображающая текущее время в формате MM: SS: T (минуты, секунды, десятые доли секунды). Метка обновляется каждые 100 миллисекунд с помощью TimerTask.

Приложение работает хорошо, и время отображается правильно, однако, есть моменты, когда метка таймера не обновляется с заданным интервалом (каждые 100 миллисекунд). Метка таймера приостанавливает (не считая) некоторое время и продолжает считать (пока все еще правильно отображает время)

Я думаю, что TimerTask не выполняется для обновления метки таймера во время этой паузы. Знаете ли вы, почему приложение действует так и как это исправить?

Ниже приведена ветка для обновления метки таймера:

public class ThreadUpdateTime 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();
  }
}

Задача таймера:

public class RecordTimer extends TimerTask  
{  
  private MyMainScreen myMainScreen;  
  public RecordTimer(MyMainScreen parent)  
  {  
    myMainScreen=parent;  
  }  

  public void run()   
  {  
    myMainScreen.iUpdateTimerLabel();  
  }  
}  

и метод iUpdateTimerLabel:

public void iUpdateTimerLabel()  
{  
//calculate : sign, sMin, sSec, sTenth     

  synchronized(Application.getEventLock())  
  {  
    lblSpotTime.setText(sign+sMin+":"+sSec+"."+sTenth+" ");  
  }    
} 

1 Ответ

2 голосов
/ 04 ноября 2010

Сначала нужно измерить его ... записать временные метки, когда ваша таймерная задача начинается и заканчивается, и посмотреть, действительно ли это проблема TimerTask. Имея это в виду, несколько вещей, которые приходят мне в голову,

  1. Ваша задача блокируется (возможно, на какой-то пользовательский интерфейс)?
  2. Есть ли другие задачи в том же Timer экземпляр? Я не знаю, указано ли это как таковое, но, вероятно, все задачи выполняются в одном потоке, поэтому, если вам мешает другая задача, ваши задачи могут не выполняться с точно заданным интервалом.
  3. Правильно ли синхронизируется TimerTask с циклом событий пользовательского интерфейса (т. Е. Обновляется ли метка в правильном runLater() или каким-либо другим способом, предоставленным пользовательским интерфейсом blackberry)? Если вы этого не делаете, цикл событий пользовательского интерфейса может не заметить, что вы изменили метку. Я думаю о Blackberry, правильная вещь - invokeLater() или, может быть, invokeAndWait(), в зависимости от того, чего вы пытаетесь достичь.

Отредактировано после отправленного кода :

Несколько полезных и актуальных ресурсов здесь .

  1. Хорошо, я бы все же сказал, чтобы снабдить ваш код какими-то журналами или вызовами println для вывода временные метки, когда он запускается.
  2. Не уверен, почему вызов schedule() находится внутри собственного Runnable ... вам это не нужно, но, возможно, ваше приложение делает это по какой-то причине, которую я не вижу. Если вы думаете, что создаете явный поток для таймера, это не так. Вероятно, вы можете просто создать Timer и вызвать schedule() из любого потока приложения, который его настраивает. Timer содержит пленную нить, которая будет выполнять эту работу, а введение в еще одну нить, вероятно, излишне и сбивает с толку.
  3. Я все еще думаю, что вы можете сделать что-то вроде:
  4. Еще одно напоминание, чтобы на самом деле ИЗМЕРЯТЬ, что делает таймер, а не полагаться на мои предположения ...

код внутри 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+" ");  
      }
    });  
} 

Ваш synchronized звонок может быть достаточным, чтобы не взорвать вещи, но это не совсем предпочтительный способ. Если поток Timer посвящен этой единственной цели, как вы видите, вы можете заменить invokeLater() на invokeAndWait(), если хотите.

Кто-то может объяснить разницу между просто удержанием блокировки пользовательского интерфейса и фактическим выполнением в потоке пользовательского интерфейса, но я предполагаю, что последний вызывает invalidate(), а первый - нет. Это объясняет, почему изменения вашего ярлыка появляются только время от времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...