Android學習筆記4-自定義CountDownTimer

想要寫一個倒計時函數(shù),思路也就是獲取系統(tǒng)時間礼殊,與倒計時時間數(shù)計算來時間倒計才菠。沒想到Google官方有CountDownTimer API茸时,代碼比較短,小白也讀的懂赋访。

CountDownTimer簡單思路:

  • 構造函數(shù)初始化倒計時總時間與間隔時間
  • 虛擬函數(shù)onTick()與onFinish()交互倒計時結果
  • 利用handler處理倒計時可都,根據(jù)系統(tǒng)時間獲取倒計時還剩余的時間,判斷反饋onTick(比如一秒tick一下)/繼續(xù)后臺倒計時/結束倒計時

但源碼也因為太簡單蚓耽,就與官方文檔的例子一樣渠牲,只能指定倒計時總時間與時間間隔。
本身自己的倒計時要求也不多步悠,就是想增加暫停與恢復倒計時功能签杈。但重載該class不太可行,主要是還需要修改handler鼎兽,干脆就直接粘貼復制該代碼答姥,添加了自己需要的幾行代碼。如此自定義后的countdownTimer代碼如下:(注釋中“!add”就是自己添加的代碼)

import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
/**
 * 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:
 *
 * <pre class="prettyprint">
 * new CountDownTimer(30000, 1000) {
 *
 *     public void onTick(long millisUntilFinished) {
 *         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
 *     }
 *
 *     public void onFinish() {
 *         mTextField.setText("done!");
 *     }
 *  }.start();
 * </pre>
 *
 * 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.
 */

/**
 * customize from CountDownTimer
 * Created by zhubingning on 16/09/16.
 */
public abstract class CustomCountDownTimer {


    /**
     * Millis since epoch when alarm should stop.
     */
    private final long mMillisInFuture;

    //!add,為了暫停時保存當前還剩下的毫秒數(shù)
    private long mCurrentMillisLeft;

    /**
     * The interval in millis that the user receives callbacks
     */
    private final long mCountdownInterval;

    private long mStopTimeInFuture;

    /**
     * boolean representing if the timer was cancelled
     */
    private boolean mCancelled = false;

    /**
     * @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ù)谚咬,(總倒計時毫秒為單位踢涌,倒計時間隔)
    public CustomCountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

    //!add, 獲取此時倒計時的總時間
    public long getCountTimes(){
        return mMillisInFuture;
    }

    /**
     * Cancel the countdown.
     */
    //取消倒計時,handler從消息隊列里取出message
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

    /**
     * Pause the countdown.
     */
    //序宦!add, 暫停,調用cancel()函數(shù)背苦, mCurrentMillisLeft為全局變量自動保存
    public synchronized final void pause() {
       cancel();
    }

    /**
     * Resume the countdown.
     */
    //互捌!add, 恢復函數(shù),根據(jù)mCurrentMillisLeft的值重新添加message開始倒計時
    public synchronized final void resume() {
        mCancelled=false;
        if (mCurrentMillisLeft <= 0) {
            onFinish();
            return ;
        }
        mStopTimeInFuture = SystemClock.elapsedRealtime() + mCurrentMillisLeft;
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return ;
    }

    /**
     * Start the countdown.
     */
    //開始倒計時行剂,handler發(fā)送消息到隊列
    public synchronized final CustomCountDownTimer 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.
     */
    //虛擬函數(shù)
    public abstract void onTick(long millisUntilFinished);

    /**
     * Callback fired when the time is up.
     */
    //虛擬函數(shù)
    public abstract void onFinish();


    private static final int MSG = 1;


    // handles counting down
    //handler
    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {

            //同步線程
            synchronized (CustomCountDownTimer.this) {
                //判斷倒計時是否已取消
                if (mCancelled) {
                    return;
                }

                //計算當前剩余毫秒數(shù)
                final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();


                //根據(jù)剩余毫秒數(shù)秕噪,或者結束倒計時,或者只延時厚宰,或者調用onTick并延時
                if (millisLeft <= 0) {
                    onFinish();
                } else if (millisLeft < mCountdownInterval) {
                    // no tick, just delay until done
                    onTick(0);//腌巾!add
                    sendMessageDelayed(obtainMessage(MSG), millisLeft);
                } else {
                    long lastTickStart = SystemClock.elapsedRealtime();
                    mCurrentMillisLeft=millisLeft;//!add
                    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);
                }
            }
        }
    };
}

p.s. 附注知識:關于handler
“異步處理大師-handler“可以關聯(lián)任意線程并添加消息(即task)到消息隊列中铲觉,當相關線程的looper循環(huán)到自己的消息時澈蝙,能夠自動執(zhí)行該消息(異步),執(zhí)行完畢后再回到looper撵幽。
特別是上面的例子中handler中有delay處理灯荧,所以單獨用handler處理比較合適。

1.handler發(fā)送消息到消息隊列中

2.handler異步處理消息

* handler&多線程的參考文獻:
android的消息處理機制(圖+源碼分析)——Looper,Handler,Message
Android之Handler用法總結

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末盐杂,一起剝皮案震驚了整個濱河市逗载,隨后出現(xiàn)的幾起案子哆窿,更是在濱河造成了極大的恐慌,老刑警劉巖厉斟,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挚躯,死亡現(xiàn)場離奇詭異,居然都是意外死亡擦秽,警方通過查閱死者的電腦和手機码荔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來号涯,“玉大人目胡,你說我怎么就攤上這事×纯欤” “怎么了誉己?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長域蜗。 經常有香客問我巨双,道長,這世上最難降的妖魔是什么霉祸? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任筑累,我火速辦了婚禮,結果婚禮上丝蹭,老公的妹妹穿的比我還像新娘慢宗。我一直安慰自己,他們只是感情好奔穿,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布镜沽。 她就那樣靜靜地躺著,像睡著了一般贱田。 火紅的嫁衣襯著肌膚如雪缅茉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天男摧,我揣著相機與錄音蔬墩,去河邊找鬼。 笑死耗拓,一個胖子當著我的面吹牛拇颅,可吹牛的內容都是我干的。 我是一名探鬼主播帆离,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔬蕊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起岸夯,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤麻献,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后猜扮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勉吻,經...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年旅赢,在試婚紗的時候發(fā)現(xiàn)自己被綠了齿桃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡煮盼,死狀恐怖短纵,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情僵控,我是刑警寧澤香到,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站报破,受9級特大地震影響悠就,放射性物質發(fā)生泄漏。R本人自食惡果不足惜充易,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一梗脾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盹靴,春花似錦炸茧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至自赔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柳琢,已是汗流浹背绍妨。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柬脸,地道東北人他去。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像倒堕,于是被迫代替她去往敵國和親灾测。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內容