倒計時器 CountDownTimer


使用介紹

開發中經常會遇到一些和倒計時有關的場景,比如發送驗證碼的按鈕,會在點擊發送后,顯示倒計時間,倒計時結束后才能夠刷新按鈕,再次允許點擊。為了不阻塞軟件的運行,又要實時刷新界面,我們通常會用到 Handler 或者 AsyncTask 等技術,自己寫邏輯實現。其實 Android 中已經封裝好了一套 CountDownTimer 來實現這個功能需求。

CountDownTimer(long millisInFuture, long countDownInterval)

CountDownTimer的兩個參數分別表示倒計時的總時間 millisInFuture 和間隔時間 countDownInterval。

具體的調用如下:

TextView vertifyBtn;
CountDownTimer timer = new CountDownTimer(60000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        vertifyBtn.setText((millisUntilFinished / 1000) + " second");
    }
    
    @Override
    public void onFinish() {
        vertifyBtn.setEnabled(true);
        vertifyBtn.setText("Send");
    }
};
timer.start();

上面的調用舉例表示總計 60 秒,每 1 秒都會執行一次 onTick 方法,其參數 millisUntilFinished 表示倒計時剩余時間毫秒數,最后倒計時結束執行 onFinish 方法。

實現原理

下面是 CountDownTimer 的源碼,代碼非常少,很好理解。從源代碼中可以看出,其實 CountDownTimer 也是利用 Handler 的消息處理機制來實現效果的。初始化設定好起始和終止時間后,每隔一定的間隔時間通過 Handler 給主線程發送消息,然后再在消息處理中回調方法。好好利用官方封裝好的工具類,可以避免我們重復的造輪子,當然了解輪子的原理就更好了!

package android.os;

public abstract class CountDownTimer {
    private final long mMillisInFuture;
    private final long mCountdownInterval;
    private long mStopTimeInFuture;
    private boolean mCancelled = false;

    public CountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

    public synchronized final CountDownTimer start() {
        mCancelled = false;
        if (mMillisInFuture <= 0) {
            onFinish();
            return this;
        }
        mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return this;
    }

    public abstract void onTick(long millisUntilFinished);

    public abstract void onFinish();

    private static final int MSG = 1;
    
    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) {
                    // no tick, just delay until done
                    sendMessageDelayed(obtainMessage(MSG), millisLeft);
                } else {
                    long lastTickStart = SystemClock.elapsedRealtime();
                    onTick(millisLeft);

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM