一、前言
原生的倒计时功能比较简单,没有暂停和重新开始计时功能,所以仿照原生的CountDownTimer做一个更好用的倒计时功能。
二、自定义类
public class LCountDownTimer {
/**
* 时间,即开始的时间,通俗来说就是倒计时总时间
*/
private long mMillisInFuture;
/**
* 布尔值,表示计时器是否被取消
* 只有调用cancel时才被设置为true
*/
private boolean mCancelled = false;
/**
* 用户接收回调的时间间隔,一般是1秒
*/
private long mCountdownInterval;
/**
* 记录暂停时候的时间
*/
private long mStopTimeInFuture;
/**
* mas.what值
*/
private static final int MSG = 520;
/**
* 暂停时,当时剩余时间
*/
private long mCurrentMillisLeft;
/**
* 是否暂停
* 只有当调用pause时,才设置为true
*/
private boolean mPause = false;
/**
* 监听listener
*/
private TimerListener mCountDownListener;
/**
* 是否创建开始
*/
private boolean isStart;
public LCountDownTimer(){
isStart = true;
}
public LCountDownTimer(long millisInFuture, long countdownInterval) {
long total = millisInFuture + 20;
this.mMillisInFuture = total;
//this.mMillisInFuture = millisInFuture;
this.mCountdownInterval = countdownInterval;
isStart = true;
}
/**
* 开始倒计时,每次点击,都会重新开始
*/
public synchronized final void start() {
if (mMillisInFuture <= 0 && mCountdownInterval <= 0) {
throw new RuntimeException("you must set the millisInFuture > 0 or countdownInterval >0");
}
mCancelled = false;
long elapsedRealtime = SystemClock.elapsedRealtime();
mStopTimeInFuture = elapsedRealtime + mMillisInFuture;
mPause = false;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
if (mCountDownListener!=null){
mCountDownListener.onStart();
}
}
/**
* 取消计时器
*/
public synchronized final void cancel() {
if (mHandler != null) {
//暂停
mPause = false;
mHandler.removeMessages(MSG);
//取消
mCancelled = true;
}
}
/**
* 按一下暂停,再按一下继续倒计时
*/
public synchronized final void pause() {
if (mHandler != null) {
if (mCancelled) {
return;
}
if (mCurrentMillisLeft < mCountdownInterval) {
return;
}
if (!mPause) {
mHandler.removeMessages(MSG);
mPause = true;
}
}
}
/**
* 恢复暂停,开始
*/
public synchronized final void resume() {
if (mMillisInFuture <= 0 && mCountdownInterval <= 0) {
throw new RuntimeException("you must set the millisInFuture > 0 or countdownInterval >0");
}
if (mCancelled) {
return;
}
//剩余时长少于
if (mCurrentMillisLeft < mCountdownInterval || !mPause) {
return;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mCurrentMillisLeft;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
mPause = false;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
synchronized (LCountDownTimer.this) {
if (mCancelled) {
return;
}
//剩余毫秒数
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
mCurrentMillisLeft = 0;
if (mCountDownListener != null) {
mCountDownListener.onFinish();
}
} else if (millisLeft < mCountdownInterval) {
mCurrentMillisLeft = 0;
// 剩余时间小于一次时间间隔的时候,不再通知,只是延迟一下
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
//有多余的时间
long lastTickStart = SystemClock.elapsedRealtime();
if (mCountDownListener != null) {
mCountDownListener.onTick(millisLeft);
}
mCurrentMillisLeft = millisLeft;
// 考虑用户的onTick需要花费时间,处理用户onTick执行的时间
// 打印这个delay时间,大概是997毫秒
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
// 特殊情况:用户的onTick方法花费的时间比interval长,那么直接跳转到下一次interval
// 注意,在onTick回调的方法中,不要做些耗时的操作
boolean isWhile = false;
while (delay < 0){
delay += mCountdownInterval;
isWhile = true;
}
if (isWhile){
}
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
/**
* 设置倒计时总时间
* @param millisInFuture 毫秒值
*/
public void setMillisInFuture(long millisInFuture) {
long total = millisInFuture + 20;
this.mMillisInFuture = total;
}
/**
* 设置倒计时间隔值
* @param countdownInterval 间隔,一般设置为1000毫秒
*/
public void setCountdownInterval(long countdownInterval) {
this.mCountdownInterval = countdownInterval;
}
/**
* 设置倒计时监听
* @param countDownListener listener
*/
public void setCountDownListener(TimerListener countDownListener) {
this.mCountDownListener = countDownListener;
}
}
最后的几个方法可以设置总时长,倒计时间隔,倒计时监听。
接口:
public interface TimerListener {
/**
* 当倒计时开始
*/
void onStart();
/**
* 当倒计时结束
*/
void onFinish();
/**
* @param millisUntilFinished 剩余时间
*/
void onTick(long millisUntilFinished);
}
使用示例:
var mCountTime: LCountDownTimer? = null
override fun initInterface() {
//倒计时相关
mCountTime = LCountDownTimer(60*1000 + 100, 1000)
btn_click_all_start.setOnClickListener {
mCountTime?.start()
}
btn_click_all_restart.setOnClickListener {
mCountTime?.resume()
}
btn_click_all_pause.setOnClickListener {
mCountTime?.pause()
}
btn_click_all_stop.setOnClickListener {
mCountTime?.cancel()
}
mCountTime?.setCountDownListener(object : TimerListener{
override fun onFinish() {
LogUtils.e("onFinish")
}
override fun onTick(millisUntilFinished: Long) {
tv_click_all_num.text = "${millisUntilFinished / 1000}, 倒计时"
LogUtils.e("onTick--${millisUntilFinished/1000}")
}
override fun onStart() {
LogUtils.e("onStart")
}
})
}
override fun onDestroy() {
super.onDestroy()
mCountTime?.run {
cancel()
}
mCountTime = null
}