简介
CounterDownTImer是Android系统自带的一个倒计时器,特别是在做app登录时会比较有用。
用法
非常简单,比如做个倒计时60s且每隔1s会刷新一下,可以这样写
new CountDownTimer(60000, 1000) {
public void onTick(long millisLeft) {
mTextField.setText("seconds millisLeft: " + millisLeft / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
CountDownTimer类的构造器接受2个参数,第一个为倒计时总时间,第二个为间隔时间单位。注意2个参数单位都是ms。当调用start方法后,系统会每间隔一段时间(第二个参数指定)调用onTrick方法,倒计时结束会执行onFinish方法;那么到底是怎么实现的呢?
下面是源码以及对源码理解所做的注释,就不再解释了
package android.os;
/*
*
* 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.
*/
public abstract class CountDownTimer {
/**
* Millis since epoch when alarm should stop.
*/
private final long mMillisInFuture;//倒计时总耗时间(单位:ms)
/**
* The interval in millis that the user receives callbacks
*/
private final long mCountdownInterval;//间隔时间(单位:ms)
private long mStopTimeInFuture;//倒计时结束时间戳(单位:ms)
/**
* boolean representing if the timer was cancelled
*/
private boolean mCancelled = false;
/**
* @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;
}
/**
* Cancel the countdown.
*/
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}
/**
* Start the countdown.
*/
public synchronized final CountDownTimer start() {
mCancelled = false;
//判断构造器接受的参数是否合法,
//如果倒计时总耗时间<=0 直接调用onFinish方法,并立即返回该对象
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();
private static final int MSG = 1;
//注意此处mHandler成员变量的构造器没有传入Looper哦
// 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 if (millisLeft < mCountdownInterval) {
//如果还剩的时间比间隔时间还小,不再调用onTick方法,延迟剩余的时间发送通知后直接执行onFinish方法
// no tick, just delay until done
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
/**
*delay = 间隔时间-onTick消耗的时间
*如果delay >=0 ,为保证onTick是严格间隔时间执行,延迟delay发送通知
*如果delay < 0, 说明执行onTick方法消耗的时间比间隔时间大,只能跳过当前时序,直接进入下一个时序
**/
// take into account user's onTick taking time to execute
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
// 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涉及到UI修改,CountDownloadTimer对象创建确保在UI线程创建
- CountDownTimer为了保持在间隔时间内准确通知onTick,会计算onTick时间,如果onTick消耗时间大于指定的间隔时间,只能在下个时间间隔内执行onTick了