- 简介:
倒计时类,提供倒计时服务,只需提供总的倒计时时间和每次的间隔,就会定时收到回调;
比如:
倒计时30s,每秒收到一个回调,结束时也收到回调
* new CountDownTimer(30000, 1000) {
*
* public void onTick(long millisUntilFinished) {
* mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
* }
*
* public void onFinish() {
* mTextField.setText("done!");
* }
* }.start();
其中2个回调是暴露接口
public abstract void onTick(long millisUntilFinished);
public abstract void onFinish();
- 源码解析
- 构造函数得到初始化参数
- start方法启动定时器,触发handler消息循环
- handler逻辑,不停的计算回调
构造函数 及初始化变量
// 倒计时总时间
private final long mMillisInFuture;
//回调时间间隔
private final long mCountdownInterval;
// 倒计时截止时刻,由mMillisInFuture计算得到
private long mStopTimeInFuture;
// 取消倒计时标志位
private boolean mCancelled = false;
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
开始倒计时
public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
// 倒计时截止时刻
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
// handler 开启消息循环处理
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
关键的handler来负责倒计时时间计算和回调
// handles counting down
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {
if (mCancelled) {
return;
}
// 1. 计算 剩余总时间
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;
// 如果剩余总时间还不足以一个时间间隔,就直接delay剩余时间 --》 onFinish
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的执行时间;(如果onTick消耗时间过多,超过了一个时间间隔,就直接略过),必须保证delay为正!
流程大约为:
- 计算剩余总时间,若<=0,则finish;
- 回调onTick,并记录onTick耗时
- 剩余总时间小于一个时间间隔 ,则延迟这部分时间(减去onTick耗时)(保证为正)--》finish
- 剩余总时间大于一个时间间隔,则以一个时间间隔减去onTick耗时作为延迟时间 --》onTick
由
if (mCancelled) {
return;
}
可知取消倒计时只需要设置mCancelled即可
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}