关于Handler的内部原理及实现可以查看——Handler机制源码之路。
CountDownTimer 是系统提供的一个倒计时类。其内部就是使用了 Handler 封装的。
1. 用法
先来看一下如何使用。
// 源码注释
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
可以看到,直接 new 一个 CountDownTimer 实例, 传入两个参数, 实现两个抽象方法onTick(long) 和 onFinish(), 然后 start()
2. 源码
接下来通过源码+注释说明参数作用。
2.1 构造方法
/**
* @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.
* 参数1 millisInfuture:这个参数代表你要倒计时的整体毫秒值,当start()开始执行时开始倒计时,当倒计时结束时回调onFinish()方法
* 参数2 countDownInterval: 代表每次onTick(long)回调的时机,每countDownInterval差值回调一次
*/
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
2.2 抽象方法
可以看到 onFinish() 和 onTick(long) 方法为抽象方法,需要子类实现。
/**
* 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();
2.3 start() 方法
/**
* Start the countdown.
*/
public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= 0) {// 如果开始的时候倒计时总时长未设置或为负数,直接结束。
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;// 当前时间+总时间,等于要停止的实际时间
// 通过Handler 发送消息,然后在Handler中真正开始计时
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
2.4 Handler 部分
// handles counting down
// 内部成员变量直接实例化,说明一个CountDownTimer对应一个Handler
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {// 这个锁我不知道为什么要加,我的理解在这个方法中一定是回调的同线程的Handler,Handler也没有声明成异步Handler,所以一定是按顺序回调
if (mCancelled) {
return;
}
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();// 要停止的实际时间-当前时间,表示开始倒计时的总时长
if (millisLeft <= 0) {
onFinish();
} else {
long lastTickStart = SystemClock.elapsedRealtime();// 上次回调时间
onTick(millisLeft);
long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;// 回调执行的时间
long delay;
if (millisLeft < mCountdownInterval) {// 需要倒计时的时间小于单次间隔
delay = millisLeft - lastTickDuration;
// 如果执行时间过长,会导致计时不准,这时直接进入下一次倒计时
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);
}
}
}
};
2.5 cancel() 方法
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}
3. 总结
很简单的一个类,就是使用Handler封装的倒计时工具。需要注意的就是
- 在 CountDownTimer 创建的时候,一定要保证所在线程的 Looper 已经开启。
- 在 Activity 注销时,记着取消定时器。
- 定时器中不要留存 Activity 的强引用。
网友评论