Android 中简单实现倒计时功能
在Android 中倒计时功能是比较普遍使用的一个功能,比如手机验证码,计时执行命令等。实现方式有Handler、Thread 等,但是实现起来都比较复杂,过于麻烦,需要自己去写很多代码。今天讲讲在Android中如何用CountDownTimer 非常简单的实现倒计时功能。
先看看CountDownTimer 类源码,我们先来熟悉它的构造,再动手。
CountDownTimer 实现倒计时功能的机制也是用Handler 消息控制,只是它帮我们已经封装好了,我们可以直接实现类提供的方法就可以写自己的业务逻辑了。
/**
* Schedule a countdown until a time in the future, with
* regular notifications on intervals along the way.
*
* Example of showing a 30 second countdown in a text field:
*
* <pre class="prettyprint">
* new CountDownTimer(30000, 1000) {
*
* public void onTick(long millisUntilFinished) {
* mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
* }
*
* public void onFinish() {
* mTextField.setText("done!");
* }
* }.start();
* </pre>
*
* The calls to {@link #onTick(long)} are synchronized to this object so that
* one call to {@link #onTick(long)} won't ever occur before the previous
* callback is complete. This is only relevant when the implementation of
* {@link #onTick(long)} takes an amount of time to execute that is significant
* compared to the countdown interval.
*/
大致描述是 设置一个倒计时时间,直到完成一个时间段的计时,并且会时时更新时间的变化,举了一个30秒倒计时的例子如下
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
我们从这个例子中可以看出,他有一个构造方法,传入了两个参数。
/**
* @param millisInFuture The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param countDownInterval The interval along the way to receive
* {@link #onTick(long)} callbacks.
*/
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
第一个参数传入设置倒计时的总时间,第二个参数传入每隔多少毫秒执行一次,注意这里传入的两个时间参数的单位都是毫秒。如我要定义一个一分的倒计时,每隔一秒执行一次,传参时就应该是 new CountDownTimer(60000, 1000)。
下面看看提供的这几个方法。
/**
* Cancel the countdown.
*/
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}
/**
* Start the countdown.
*/
public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
/**
* Callback fired on regular interval.
* @param millisUntilFinished The amount of time until finished.
*/
public abstract void onTick(long millisUntilFinished);
/**
* Callback fired when the time is up.
*/
public abstract void onFinish();
cancel() 从字面上也理解到,它就是取消倒计时的意思.通过Handler removeMessages 取消正在执行的倒计时任务。
start() 开始执行倒计时。通过Handler sendMessage 发送消息并开始执行倒计时任务。
onTick() 倒计时更新。这里可以得到距离完成倒计时还剩多少时间。
onFinish() 倒计时完成后的回调。
我们再来看看Handler 实现部分
// handles counting down
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {
if (mCancelled) {
return;
}
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
onFinish();
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
// take into account user's onTick taking time to execute
long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
long delay;
if (millisLeft < mCountdownInterval) {
// just delay until done
delay = millisLeft - lastTickDuration;
// special case: user's onTick took more than interval to
// complete, trigger onFinish without delay
if (delay < 0) delay = 0;
} else {
delay = mCountdownInterval - lastTickDuration;
// special case: user's onTick took more than interval to
// complete, skip to next interval
while (delay < 0) delay += mCountdownInterval;
}
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
这里主要是轮询计算时间,调用 onTick() 方法更新当前倒计时时间,当mStopTimeInFuture 减去 SystemClock.elapsedRealtime()(boot 以来经过的毫秒数)小于等于 0 时 ,则调用 onFinish()。
下面我们简单写一个实现倒计时的demo
为了代码维护和重用,我这里写一个公共的倒计时 CommonCountDownTimer 类,代码如下:
import android.os.CountDownTimer;
/**
* 公共倒计时类
*/
public class CommonCountDownTimer extends CountDownTimer {
private OnCountDownTimerListener countDownTimerListener;
public void setCountDownTimerListener(OnCountDownTimerListener listener) {
this.countDownTimerListener = listener;
}
/**
* @param millisInFuture The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param countDownInterval The interval along the way to receive
* {@link #onTick(long)} callbacks.
*/
public CommonCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
if (null != countDownTimerListener) {
countDownTimerListener.onTick(millisUntilFinished);
}
}
@Override
public void onFinish() {
if (null != countDownTimerListener){
countDownTimerListener.onFinish();
}
}
public interface OnCountDownTimerListener {
/**
* 更新倒计时时间
*
* @param millisUntilFinished
*/
void onTick(long millisUntilFinished);
/**
* 完成倒计时
*/
void onFinish();
}
}
这里的CommonCountDownTimer 类继承了 android.os.CountDownTimer 类,我定义了一个 OnCountDownTimerListener 接口主要来监听 onTick(long millisUntilFinished) 和 onFinish() ,这样可以把业务逻辑分开来处理。
开始使用
private void initCountDownTimer() {
mCountDownTimer = new CommonCountDownTimer(60000, 1000);
mCountDownTimer.setCountDownTimerListener(new CommonCountDownTimer.OnCountDownTimerListener() {
@Override
public void onTick(long millisUntilFinished) {
tv_time.setText("倒计时:" + millisUntilFinished / 1000);
}
@Override
public void onFinish() {
tv_time.setText("倒计时: 00");
}
});
}
就是这么简单,主要需要理解 CountDownTimer 这个类,理解了之后就可以根据自己的业务场景灵活使用了。
由于本人很菜,有些地方认识理解不对的地方欢迎,谢谢大家指正。
觉得还行的可以关注公众号好 ProgrammerRan 查看更多内容。