This is named after the Pinwheel toy.
Another reasonable name might be "Resettable Timer."
You can picture spinning it. Before it stops spinning it, you help it to keep going, so that it won't stop.
final class PinwheelTimer {
private final HandlerThread handlerThread;
private final Handler countDownHandler;
private final Runnable onTimedOut;
private final long timeout;
// Create a new pinwheel timer.
PinwheelTimer(Runnable onTimedOut, long timeout) {
this.handlerThread = new HandlerThread("PinwheelTimer");
this.handlerThread.start();
this.countDownHandler = new Handler(handlerThread.getLooper());
this.onTimedOut = onTimedOut;
this.timeout = timeout;
}
// Start the pinwheel timer.
synchronized void start() {
countDownHandler.postDelayed(onTimedOut, timeout);
}
// Stop the timer without calling back the aciton.
// This instance cannot be used again.
syncrhonized void stop() {
countDownHandler.removeCallbacksAndMessages(null);
handlerThread.quit();
}
// Reset the timer, without calling back the action.
// The action will be called when the full original timeout elapses
// beyond the time of this call.
// This is the "pinwheel" part.
syncrhonized void reset() {
countDownHandler.removeCallbacksAndMessages(null);
start();
}
}
// Timer will never count down until started
PinwheelTimer timer = new PinwheelTimer(() -> Log.i(TAG, "Bam!"), 1_000);
// Timer will count down in 1_000ms (constructor arg)
timer.start();
// Wait for a bit
Thread.sleep(300);
// Timer has 700ms left.
timer.reset();
// timer will count down in 1_000 ms from now.