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:**

* new CountDownTimer(30000, 1000) {** public void onTick(long millisUntilFinished) {* mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);* }** public void onFinish() {* mTextField.setText("done!");* }* }.start();* ** 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秒倒計時的例子如下

<code> new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}

public void onFinish() {
mTextField.setText("done!");
}
}.start();/<code>

從這個例子中可以看出,他有一個構造方法,傳入了兩個參數。

<code>/**
* @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;
}/<code>

第一個參數傳入設置倒計時的總時間,第二個參數傳入每隔多少毫秒執行一次,注意這裡傳入的兩個時間參數的單位都是毫秒。如我要定義一個一分的倒計時,每隔一秒執行一次,傳參時就應該是 new CountDownTimer(60000, 1000)。

下面看看提供的這幾個方法。

<code>/**
* 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();/<code>

cancel() 從字面上也理解到,它就是取消倒計時的意思.通過Handler removeMessages 取消正在執行的倒計時任務。start() 開始執行倒計時。通過Handler sendMessage 發送消息並開始執行倒計時任務。onTick() 倒計時更新。這裡可以得到距離完成倒計時還剩多少時間。onFinish() 倒計時完成後的回調。

我們再來看看Handler 實現部分

<code> // 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);
}
}
}
};/<code>

這裡主要是輪詢計算時間,調用 onTick() 方法更新當前倒計時時間,當mStopTimeInFuture 減去 SystemClock.elapsedRealtime()(boot 以來經過的毫秒數)小於等於 0 時 ,則調用 onFinish()。

下面我們簡單寫一個實現倒計時的demo 為了代碼維護和重用,我這裡寫一個公共的倒計時 CommonCountDownTimer 類,代碼如下:

<code>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();
}
}
/<code>

這裡的CommonCountDownTimer 類繼承了 android.os.CountDownTimer 類,我定義了一個 OnCountDownTimerListener 接口主要來監聽 onTick(long millisUntilFinished) 和 onFinish() ,這樣可以把業務邏輯分開來處理。


開始使用

<code> 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");
}
});
}/<code>

就是這麼簡單,主要需要理解 CountDownTimer 這個類,理解了之後就可以根據自己的業務場景靈活使用了。由於本人很菜,有些地方認識理解不對的地方歡迎,謝謝大家指正。


題圖: pixabay