2016-07-08 1 views
2

я смотрел на ScheduledExecutorService only loops onceScheduledExecutorService ли только Обжиг После

Но это, кажется, не решить мою проблему.

У меня есть пользовательский таймер, и когда я ударил start предполагается стрелять обратного вызова каждую секунду:

/** 
* Starts the timer. If the timer was already running, this call is ignored. 
*/ 
public void start() 
{ 
    if (_isRunning) 
    { 
     return; 
    } 

    _isRunning = true; 

    // Schedules repeated task that fires each time at the interval given 
    Log.d("Timer", "Starting execution"); 
    _future = _execService.scheduleWithFixedDelay(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      Log.d("Timer", "Fire"); 

      _elapsedTime += PausableTimer.this._interval; 

      // If time has exceeded duration, stop timer 
      if (_duration > 0 && _elapsedTime >= _duration) 
      { 
       Log.d("Timer", "Finish"); 
       onFinish(); 
       _future.cancel(false); 
      } 
     } 
    }, 0, _interval, TimeUnit.MILLISECONDS); 
} 

Вот как я взываю таймер:

_timer = new PausableTimer(1000, PausableTimer.DURATION_INFINITY); 
    _timer.start(); 

Это создает таймер, который срабатывает в течение 1000 миллисекундных интервалов для бездействия.

Однако мои журналы показывают только стрельбу один раз. Журнал «Finish» не появляется, поэтому я знаю, что он не закончился.

Вы знаете, почему это срабатывает только один раз?

Update

/** 
* Timer that can play and pause. 
*/ 
public class PausableTimer extends Timer 
{ 
    public static final int DURATION_INFINITY = -1; 

    private Callbacks.VoidCallback _onTick; 
    private Callbacks.VoidCallback _onFinish; 

    private volatile boolean _isRunning = false; 
    private long _interval; 
    private long _elapsedTime; 
    private long _duration; 
    private ScheduledExecutorService _execService = Executors.newSingleThreadScheduledExecutor(); 
    private Future<?> _future = null; 

    /** 
    * Creates a pausable timer. 
    * @param interval The time gap between each tick in millis. 
    * @param duration The period in millis for which the timer should run. 
    * Set it to {@code Timer#DURATION_INFINITY} if the timer has to run indefinitely. 
    */ 
    public PausableTimer(long interval, long duration) 
    { 
     _interval = interval; 
     _duration = duration; 
     _elapsedTime = 0; 
     _isRunning = false; 
    } 




    /// LIFE CYCLE 



    /** 
    * Starts the timer. If the timer was already running, this call is ignored. 
    */ 
    public void start() 
    { 
     if (_isRunning) 
     { 
      Log.d("Timer", "already started running"); 
      return; 
     } 

     _isRunning = true; 

     // Schedules repeated task that fires each time at the interval given 
     Log.d("Timer", "Starting execution"); 
     _future = _execService.scheduleWithFixedDelay(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       Log.d("Timer", "Fire"); 
       onTick(); 

       _elapsedTime += PausableTimer.this._interval; 

       // If time has exceeded duration, stop timer 
       if (_duration > 0 && _elapsedTime >= _duration) 
       { 
        Log.d("Timer", "Finish"); 
        onFinish(); 
        _future.cancel(false); 
       } 
      } 
     }, 0, PausableTimer.this._interval, TimeUnit.MILLISECONDS); 
    } 

    /** 
    * Pauses the timer. 
    */ 
    public void pause() 
    { 
     if(!_isRunning) 
     { 
      return; 
     } 

     _future.cancel(false); 
     _isRunning = false; 
    } 

    /** 
    * Resumes the timer if it was paused, else starts the timer. 
    */ 
    public void resume() 
    { 
     start(); 
    } 

    /** 
    * Called periodically with the _interval set as the delay between subsequent calls. 
    * Fires tick callback if set. 
    */ 
    private void onTick() 
    { 
     if (_onTick != null) 
     { 
      _onTick.callback(); 
     } 
    } 

    /** 
    * Called once the timer has run for the specified _duration. 
    * If the _duration was set as infinity, then this method is never called. 
    * Fires finished callback if set. 
    */ 
    protected void onFinish() 
    { 
     if (_onFinish != null) 
     { 
      _onFinish.callback(); 
     } 

     _isRunning = false; 
    } 

    /** 
    * Stops the timer. If the timer is not running, then this call does nothing. 
    */ 
    public void cancel() 
    { 
     pause(); 
     _elapsedTime = 0; 
    } 




    /// GETTERS 



    /** 
    * @return the elapsed time (in millis) since the start of the timer. 
    */ 
    public long getElapsedTime() 
    { 
     return _elapsedTime; 
    } 

    /** 
    * @return the time remaining (in millis) for the timer to stop. 
    * If the _duration was set to {@code Timer#DURATION_INFINITY}, then -1 is returned. 
    */ 
    public long getRemainingTime() 
    { 
     if (_duration <= PausableTimer.DURATION_INFINITY) 
     { 
      return PausableTimer.DURATION_INFINITY; 
     } 

     return _duration - _elapsedTime; 
    } 






    /// BINDERS 



    /** 
    * @return true if the timer is currently running, and false otherwise. 
    */ 
    public boolean isRunning() 
    { 
     return _isRunning; 
    } 

    /** 
    * Binds onTick callback. 
    */ 
    public void bindOnTick(Callbacks.VoidCallback callback) 
    { 
     _onTick = callback; 
    } 

    /** 
    * Binds onFinish callback. 
    * @param callback 
    */ 
    public void bindOnFinish(Callbacks.VoidCallback callback) 
    { 
     _onFinish = callback; 
    } 
} 

Вот типичный журнал. В основном то, что происходит, я начинаю, подождите 10-15 секунд, а затем снова запустите его. Он должен срабатывать каждую секунду. Однако он срабатывает один или два раза, затем не запускается до его перезапуска.

D/Таймер: Сброс таймера

D/Таймер: Начиная исполнение

D/Таймер: Огонь

D/Таймер: Сброс таймера

D/Таймер: Запуск исполнение

D/Таймер: Огонь

D/Таймер: Огонь

D/Таймер: Сброс таймера

D/Таймер: Начиная исполнение

Чтобы быть очень ясно, вот некоторые ссылающееся код я использую:

private void restartTimer() 
{ 
    if (_timer != null) 
    { 
     _timer.cancel(); 
    } 
    Log.d("Timer", "Reset timer"); 

    _timer = new PausableTimer(1000, PausableTimer.DURATION_INFINITY); 
    _timer.bindOnTick(new Callbacks.VoidCallback() 
    { 
     @Override 
     public void callback() 
     { 
      decrementTimeRemaining(); 
     } 
    }); 
    _timer.start(); 
} 

РЕШЕНИЕ

После выяснения , что onTick() вызова в моих run() причиняли нить, чтобы остановить, я решил это диспетчеризация onTick() вызова в основной поток:

 _future = _execService.scheduleWithFixedDelay(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      Log.d("Timer", "Run begin"); 

      Runnable task = new Runnable() 
      { 
       @Override 
       public void run() 
       { 
        Log.d("Timer", "Main thread tick"); 
        PausableTimer.this.onTick(); 
       } 
      }; 
      Handler mainHandler = new Handler(Looper.getMainLooper()); 
      mainHandler.post(task); 

      _elapsedTime += PausableTimer.this._interval; 
      Log.d("Timer", "Run middle"); 


      // If time has exceeded duration, stop timer 
      if (_duration > 0 && _elapsedTime >= _duration) 
      { 
       Log.d("Timer", "Finish"); 
       onFinish(); 
       _future.cancel(false); 
      } 
     } 
    }, 0, PausableTimer.this._interval, TimeUnit.MILLISECONDS); 
+0

Если она не закончилась, то, возможно, это может предотвратить JVM от порождая новую нить. Почему он не закончил? –

+0

Убедитесь, что исключение не выбрано в 'onFinish' или других частях runnable. –

+0

Спасибо, я посмотрю на это, когда вернусь в офис! – Aggressor

ответ

1

Очень интересная причина проблемы (для меня как минимум).

Этот вопрос был мой onTick() обратный вызов, который я стрелял:

я заметил что-то очень странное с моими бревнами. В run() бревна перед onTick() палили, и те, где под ним не:

Log.d("Timer", "Starting execution"); 
    _future = _execService.scheduleWithFixedDelay(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      Log.d("Timer", "Run begin"); // fires 

      onTick(); // when I remove this, all below logs fire! 

      _elapsedTime += PausableTimer.this._interval; 
      Log.d("Timer", "Run middle"); // didn't fire 
      Log.d("Timer", "Elapsed time " + _elapsedTime); // didn't fire 
      Log.d("Timer", "Duration " + _duration); // didn't fire 

      // If time has exceeded duration, stop timer 
      if (_duration > 0 && _elapsedTime >= _duration) 
      { 
       Log.d("Timer", "Finish"); // didn't fire 
       onFinish(); 
       _future.cancel(false); 
      } 

      Log.d("Timer", "Run End"); // didn't fire 
     } 
    }, 0, PausableTimer.this._interval, TimeUnit.MILLISECONDS); 

Когда я удалил onTick() все журналы обжигали.

Я подозреваю, что что-то оборвалось, когда я пытаюсь пойти по главной теме отсюда с onTick().

Я еще не совсем уверен, но это причина того, что таймер только стрелял один раз, вызов onTick() вызывает его.

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

Решение Отправляется обратного вызова на главном потоке:

_future = _execService.scheduleWithFixedDelay(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      Log.d("Timer", "Run begin"); 

      Runnable task = new Runnable() 
      { 
       @Override 
       public void run() 
       { 
        Log.d("Timer", "Main thread tick"); 
        PausableTimer.this.onTick(); 
       } 
      }; 
      Handler mainHandler = new Handler(Looper.getMainLooper()); 
      mainHandler.post(task); 

      _elapsedTime += PausableTimer.this._interval; 
      Log.d("Timer", "Run middle"); 


      // If time has exceeded duration, stop timer 
      if (_duration > 0 && _elapsedTime >= _duration) 
      { 
       Log.d("Timer", "Finish"); 
       onFinish(); 
       _future.cancel(false); 
      } 
     } 
    }, 0, PausableTimer.this._interval, TimeUnit.MILLISECONDS); 
0

1) Вы установить _isRunning = true; и никогда не сбросить это false;

2) Где вы устанавливаете _duration? Если это 0, ваш таймер никогда не закончится.

3) Вы используете _interval и PausableTimer.this._interval: вы хотите сделать это?

+0

1) Да, я хотел сфокусировать это на «запуске» сервиса, он установлен на false на финише 2) Его набор равен -1, который является бесконечным, я считаю 3) Вы правы, я установил что явным образом, чтобы убедиться, но ничего не изменило Таймер все еще срабатывает один или два раза и никогда не запускает 'onFinish'. – Aggressor

+0

Я обновил свой код, чтобы показать весь пакет – Aggressor