原生的倒计时功能比较简单,没有暂停和重新开始计时功能,所以仿照原生的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() {
@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 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);
}
使用比较简单,这里做个简单的 demo。
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()
}
}