я смотрел на 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);
Если она не закончилась, то, возможно, это может предотвратить JVM от порождая новую нить. Почему он не закончил? –
Убедитесь, что исключение не выбрано в 'onFinish' или других частях runnable. –
Спасибо, я посмотрю на это, когда вернусь в офис! – Aggressor