一、前言
原生的倒计时功能比较简单,没有暂停和重新开始计时功能,所以仿照原生的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() {@Overridepublic 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? = nulloverride 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}
