想要寫一個倒計時函數(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用法總結