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


    分享到:


    相關文章: