2016-07-08 57 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毫秒的時間間隔內啓動,以實現真實。

但是我的日誌只顯示它發射一次。 「完成」日誌沒有出現,所以我知道它還沒有結束。

你知道這是爲什麼只發射一次嗎?

更新

/** 
* 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(); 
} 

SOLUTION

盤算後出了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'或可運行的其他部分沒有拋出異常。 –

+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)您正在使用_intervalPausableTimer.this._interval:你的意思是這樣做嗎?

+0

1)是的,我想把重點放在服務的'運行'上,它在完成時設置爲false 2)它設置爲-1,這是無窮大,我相信 3)你是對的,我設置爲明確地確定,但它沒有改變任何東西 計時器仍會觸發一次或兩次,並且永遠不會觸發'onFinish'。 – Aggressor

+0

我更新了我的代碼以顯示整個包 – Aggressor