想要写一个倒计时函数,思路也就是获取系统时间,与倒计时时间数计算来时间倒计。没想到Google官方有CountDownTimer API,代码比较短,小白也读的懂。
CountDownTimer简单思路:
- 构造函数初始化倒计时总时间与间隔时间
- 虚拟函数onTick()与onFinish()交互倒计时结果
- 利用handler处理倒计时,根据系统时间获取倒计时还剩余的时间,判断反馈onTick(比如一秒tick一下)/继续后台倒计时/结束倒计时
但源码也因为太简单,就与官方文档的例子一样,只能指定倒计时总时间与时间间隔。
本身自己的倒计时要求也不多,就是想增加暂停与恢复倒计时功能。但重载该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,为了暂停时保存当前还剩下的毫秒数
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.
*/
//构造函数,(总倒计时毫秒为单位,倒计时间隔)
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()函数, mCurrentMillisLeft为全局变量自动保存
public synchronized final void pause() {
cancel();
}
/**
* Resume the countdown.
*/
//!add, 恢复函数,根据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发送消息到队列
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.
*/
//虚拟函数
public abstract void onTick(long millisUntilFinished);
/**
* Callback fired when the time is up.
*/
//虚拟函数
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;
}
//计算当前剩余毫秒数
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
//根据剩余毫秒数,或者结束倒计时,或者只延时,或者调用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“可以关联任意线程并添加消息(即task)到消息队列中,当相关线程的looper循环到自己的消息时,能够自动执行该消息(异步),执行完毕后再回到looper。
特别是上面的例子中handler中有delay处理,所以单独用handler处理比较合适。
* handler&多线程的参考文献:
android的消息处理机制(图+源码分析)——Looper,Handler,Message
Android之Handler用法总结