關(guān)于Handler的內(nèi)部原理及實(shí)現(xiàn)可以查看——Handler機(jī)制源碼之路。
CountDownTimer 是系統(tǒng)提供的一個倒計(jì)時類。其內(nèi)部就是使用了 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 實(shí)例, 傳入兩個參數(shù), 實(shí)現(xiàn)兩個抽象方法onTick(long) 和 onFinish(), 然后 start()
2. 源碼
接下來通過源碼+注釋說明參數(shù)作用。
2.1 構(gòu)造方法
/**
* @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.
* 參數(shù)1 millisInfuture:這個參數(shù)代表你要倒計(jì)時的整體毫秒值,當(dāng)start()開始執(zhí)行時開始倒計(jì)時,當(dāng)?shù)褂?jì)時結(jié)束時回調(diào)onFinish()方法
* 參數(shù)2 countDownInterval: 代表每次onTick(long)回調(diào)的時機(jī),每countDownInterval差值回調(diào)一次
*/
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
2.2 抽象方法
可以看到 onFinish() 和 onTick(long) 方法為抽象方法,需要子類實(shí)現(xiàn)。
/**
* 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) {// 如果開始的時候倒計(jì)時總時長未設(shè)置或?yàn)樨?fù)數(shù),直接結(jié)束。
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;// 當(dāng)前時間+總時間,等于要停止的實(shí)際時間
// 通過Handler 發(fā)送消息,然后在Handler中真正開始計(jì)時
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
2.4 Handler 部分
// handles counting down
// 內(nèi)部成員變量直接實(shí)例化,說明一個CountDownTimer對應(yīng)一個Handler
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {// 這個鎖我不知道為什么要加,我的理解在這個方法中一定是回調(diào)的同線程的Handler,Handler也沒有聲明成異步Handler,所以一定是按順序回調(diào)
if (mCancelled) {
return;
}
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();// 要停止的實(shí)際時間-當(dāng)前時間,表示開始倒計(jì)時的總時長
if (millisLeft <= 0) {
onFinish();
} else {
long lastTickStart = SystemClock.elapsedRealtime();// 上次回調(diào)時間
onTick(millisLeft);
long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;// 回調(diào)執(zhí)行的時間
long delay;
if (millisLeft < mCountdownInterval) {// 需要倒計(jì)時的時間小于單次間隔
delay = millisLeft - lastTickDuration;
// 如果執(zhí)行時間過長,會導(dǎo)致計(jì)時不準(zhǔn),這時直接進(jìn)入下一次倒計(jì)時
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. 總結(jié)
很簡單的一個類,就是使用Handler封裝的倒計(jì)時工具。需要注意的就是
- 在 CountDownTimer 創(chuàng)建的時候,一定要保證所在線程的 Looper 已經(jīng)開啟。
- 在 Activity 注銷時,記著取消定時器。
- 定時器中不要留存 Activity 的強(qiáng)引用。