前言
原生的倒计时功能比较简单,没有暂停和重新开始计时功能,所以仿照原生的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;private 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;if (mCountDownListener!=null){mCountDownListener.onCancel();}}}/*** 按一下暂停,再按一下继续倒计时*/public synchronized final void pause() {if (mHandler != null) {if (mCancelled) {return;}if (mCurrentMillisLeft < mCountdownInterval) {return;}if (!mPause) {mHandler.removeMessages(MSG);mPause = true;if (mCountDownListener!=null){mCountDownListener.onPause();}}}}/*** 恢复暂停,开始*/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;if (mCountDownListener!=null){mCountDownListener.onResume();}}@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 abstract class TimerListener {/*** 当倒计时开始*/public void onStart(){}/*** 当倒计时恢复暂停*/public void onResume(){}/*** 当倒计时暂停*/public void onPause(){}/*** 当倒计时结束*/public void onFinish(){}/*** 当倒计时取消*/public void onCancel(){}/**倒计时进行中* @param millisUntilFinished 剩余时间*/public abstract void onTick(long millisUntilFinished);}
使用示例
class CountDownActivity: AppCompatActivity(R.layout.activity_countdown) {//初始化倒计时相关private val mLTime by lazy {LCountDownTimer(9*1000 + 100, 1000)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)btnCountdownStart.setOnClickListener {mLTime.start()}btnCountdownPause.setOnClickListener {mLTime.pause()}btnCountdownResume.setOnClickListener {mLTime.resume()}btnCountdownCancel.setOnClickListener {mLTime.cancel()}btnCountdownStart2.setOnClickListener {mLTime.start()}//时间的监听mLTime.setCountDownListener(object :TimerListener(){override fun onTick(millisUntilFinished: Long) {Log.e(TAG, "onTick: $millisUntilFinished");tvCountDownTime.text = "倒计时: ${millisUntilFinished/1000}"}override fun onStart() {super.onStart()Log.e(TAG, "onStart: ");}override fun onResume() {super.onResume()Log.e(TAG, "onResume: ");}override fun onPause() {super.onPause()Log.e(TAG, "onPause: ");}override fun onFinish() {super.onFinish()Log.e(TAG, "onFinish: ");tvCountDownTime.text = "倒计时结束"}override fun onCancel() {super.onCancel()Log.e(TAG, "onCancel: ");tvCountDownTime.text = "倒计时取消"}})}override fun onDestroy() {super.onDestroy()mLTime.cancel()}}
