我看着 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);
如果還沒有結束,那麼也許這可以防止JVM產生一個新的線程。爲什麼沒有完成? –
檢查'onFinish'或可運行的其他部分沒有拋出異常。 –
謝謝,我回到辦公室時會看看這個! – Aggressor