Java/Android 自定义倒计时器






3.67/5 (5投票s)
一个在 Java/Android 中可以动态修改计时器的自定义倒计时器
引言
由于我对一个 Android 应用程序的需求,我遇到了一个需要倒计时器的情况,该倒计时器的计时器值可以在不重新创建计时器的情况下进行修改。例如,如果首先为10分钟的持续时间创建一个倒计时器,那么在用户/应用程序逻辑需求的处理过程中,我应该能够将此持续时间从10分钟修改为14分钟。Android 提供了一个高效的 CountDownTimer
类,它作为一个普通的计时器很好,但是它没有提供修改持续时间的特定功能。如果需要,您需要取消当前的计时器实例,然后使用更改后的持续时间创建另一个计时器实例。
背景
依我看来,这种需求非常简单,易于编码,而且使用频率很高,应该作为一个标准类提供。在我的搜索过程中,我发现它在任何地方都不可用。我想到了创建一个 CountDownTimer
来提供这个功能。我不想重新发明轮子,因此采用了 Android 提供的 CountDownTimer
类作为基本结构,并做了一些基本区别。Android 提供的类使用 Handler 来生成计时器事件,而拟议的类使用 ScheduledExectuorService
来执行此操作。
Using the Code
下面显示的代码是为 Android 开发的。但是,它也可以用于 Java 应用程序,只需进行小的调整,例如删除特定于 Android 的构造,例如 Handler。
正如预期的那样,倒计时器为调用者提供了以下行为
- 能够为指定的持续时间启动计时器
- 如果需要,能够在指定持续时间之前取消计时器
- 当指定的持续时间到期时,应该自动停止
- 能够生成事件,从而以调用者指定的间隔定期调用回调
除了这些功能外,此倒计时器还提供
- 能够在计时器仍在运行的情况下延长持续时间
代码说明
TimerTickListener
- 此接口的实现应该在构造过程中提供给计时器。它提供回调方法,这些方法在各种情况下被调用,例如,onTick
在定期生成tick
事件时被调用,当计时器的持续时间到期时调用onFinish
,当计时器被强制取消时调用onCancel
。TimerRunnable
- 这是计时器的核心,它提供了由调度程序定期执行的代码。在这里,我们加入了计时器根据计时器的当前状态以我们想要的方式运行的逻辑。您一定已经注意到,此代码通过将此执行发布到主线程处理程序来在主线程中执行。这是我的应用程序在主线程中执行的要求,您可以选择根据您的要求在同一线程中执行此操作。TimerRunnable
的run
方法标识计时器的状态并相应地采取行动。- 如果状态被取消,它将调用
TimerTickListener
回调的onCancel
方法并关闭调度程序。 - 如果持续时间已到期,它将调用
TimerTickListener
回调的onFinish
方法并关闭调度程序。 - 否则,它只是调用
TimerTickListener
回调的onTick
方法,并传递计时器到期前的剩余时间。
- 如果状态被取消,它将调用
构造函数
- 除了设置各种实例变量,获取TimerTickListener
的回调实现并将其保存起来之外,它所做的重要事情是创建一个分配给实例变量调度程序的SingleThreadScheduledExecutor
。Start
- 当调用此方法时,构造函数中创建的调度程序被安排以构造函数中传递的定期时间间隔运行,并调用内部可运行类TimerRunnable
的run
方法。onCancel
- 这将计时器置于取消状态extendTimer
- 这会将timer
的持续时间延长到传递给此方法的数量。
/**
* Implementation of a timer which allows the duration of timer to be modified dynamically
*/
public class CustomCountDownTimer {
//thread on which the callbacks will be called
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
//listener interface which is to be implemented by the users of the count down timer
public interface TimerTickListener{
/**
* Callback on each tick
* @param millisLeft time left in millisec for the timer to shutdown
*/
public void onTick(long millisLeft);
/**
* Callback to be invokded when timer's time finishes
*/
public void onFinish();
/**
* Callback to be invokded when timer is canceled
*/
public void onCancel();
}
/**
* Inner class which delegates the events to callbacks provided in the TimerTickListener
*/
private class TimerRunnable implements Runnable{
public void run(){
mainThreadHandler.post(new Runnable() {
long millisLeft = stopTimeInFuture - SystemClock.elapsedRealtime();
@Override
public void run() {
if (isCancelled){
//shutdown the scheduler
tickListener.onCancel();
scheduler.shutdown();
}
else if (millisLeft <= 0) {
tickListener.onFinish();
scheduler.shutdown();
}
else{
tickListener.onTick(millisLeft);
}
}
});
}
}
//Millis since epoch when alarm should stop.
private long millisInFuture;
//The interval in millis that the user receives callbacks
private final long countdownInterval;
//the time at which timer is to stop
private long stopTimeInFuture;
//boolean representing if the timer was cancelled
private boolean isCancelled = false;
//listener which listens to the timer events
private TimerTickListener tickListener;
//scheduler which provides the thread to create timer
private ScheduledExecutorService scheduler;
/**
* Constructor
* @param millisInFuture time in millisec for which timer is to run
* @param countDownInterval interval frequency in millisec at which the callback will be invoked
* @param tickListener implementation of TimerTickListener which provides callbacks code
*/
public CustomCountDownTimer(long millisInFuture, long countDownInterval,
TimerTickListener tickListener) {
this.millisInFuture = millisInFuture;
stopTimeInFuture = SystemClock.elapsedRealtime() + this.millisInFuture;
countdownInterval = countDownInterval;
this.tickListener = tickListener;
scheduler = Executors.newSingleThreadScheduledExecutor();
}
/**
* Start the countdown.
*/
public synchronized void start() {
isCancelled = false;
scheduler.scheduleWithFixedDelay(new TimerRunnable(), 0, countdownInterval,
TimeUnit.MILLISECONDS);
}
/**
* Cancels the countdown timer
*/
public synchronized final void cancel() {
isCancelled = true;
}
/**
* Extends the time of the countdown timer
* @param delta time in millisec by which timer is to be extended
*/
public void extendTime(long delta){
stopTimeInFuture = stopTimeInFuture + delta;
millisInFuture = millisInFuture + delta;
}
}