preface
The native countdown function is relatively simple, there is no pause and restart timer function, so copy the native CountDownTimer to make a more useful countdown function.
Custom class
public class LCountDownTimer {
/** ** time, i.e. the start time, commonly known as the total countdown time */
private long mMillisInFuture;
/** * Boolean value indicating whether the timer is cancelled * is set to true only when cancel is called
private boolean mCancelled = false;
/** * The interval at which the user receives the callback, usually 1 second */
private long mCountdownInterval;
/** * Record the pause time */
private long mStopTimeInFuture;
/** * mas.what value */
private static final int MSG = 520;
/** ** pause when the remaining time */
private long mCurrentMillisLeft;
/** * Pause is set to true only when pause is called
private boolean mPause = false;
/** * listener */
private TimerListener mCountDownListener;
/** * Whether to create start */
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;
}
/** * start the countdown, each click, will restart */
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(); }}/** * cancel the timer */
public synchronized final void cancel() {
if(mHandler ! =null) {
/ / pause
mPause = false;
mHandler.removeMessages(MSG);
/ / cancel
mCancelled = true;
if(mCountDownListener! =null){ mCountDownListener.onCancel(); }}}/** * press pause, press again to continue countdown */
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(); }}}}/** * resume pause, start */
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;
}
// The remaining time is less than that
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;
}
// Number of milliseconds left
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
mCurrentMillisLeft = 0;
if(mCountDownListener ! =null) { mCountDownListener.onFinish(); }}else if (millisLeft < mCountdownInterval) {
mCurrentMillisLeft = 0;
// If the remaining time is less than one interval, no notification will be given
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
// Have time to spare
long lastTickStart = SystemClock.elapsedRealtime();
if(mCountDownListener ! =null) {
mCountDownListener.onTick(millisLeft);
}
mCurrentMillisLeft = millisLeft;
// Consider how long the user's onTick takes to execute
// Print this delay, about 997 milliseconds
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
// Special case: if the user's onTick method takes longer than interval, skip to the next interval
// Note that in the onTick callback method, do not do time-consuming operations
boolean isWhile = false;
while (delay < 0){
delay += mCountdownInterval;
isWhile = true;
}
if(isWhile){ } sendMessageDelayed(obtainMessage(MSG), delay); }}}};/** * Set the total countdown time *@paramMillisieverts */
public void setMillisInFuture(long millisInFuture) {
long total = millisInFuture + 20;
this.mMillisInFuture = total;
}
/** * Sets the countdown interval value *@paramCountdownInterval Specifies the interval. The value is 1000 milliseconds */
public void setCountdownInterval(long countdownInterval) {
this.mCountdownInterval = countdownInterval;
}
/** * set timer listener *@param countDownListener listener
*/
public void setCountDownListener(TimerListener countDownListener) {
this.mCountDownListener = countDownListener; }}Copy the code
Abstract classes used:
public abstract class TimerListener {
/** ** when the countdown starts */
public void onStart(){
}
/** * when the countdown resumes pause */
public void onResume(){
}
/** * when the countdown is paused */
public void onPause(){
}
/** ** When the countdown ends */
public void onFinish(){
}
/** ** When the countdown is cancelled */
public void onCancel(){
}
/** Countdown is in progress *@paramZipuntilfinished */
public abstract void onTick(long millisUntilFinished);
}
Copy the code
Use the sample
It’s easy to use, so here’s a simple demo.
class CountDownActivity: AppCompatActivity(R.layout.activity_countdown) {
// Initialize the 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()
}
// Time monitor
mLTime.setCountDownListener(object :TimerListener(){
override fun onTick(millisUntilFinished: Long) {
Log.e(TAG, "onTick: $millisUntilFinished");
tvCountDownTime.text = "Countdown:${millisUntilFinished/1000}"
}
override fun onStart(a) {
super.onStart()
Log.e(TAG, "onStart: ");
}
override fun onResume(a) {
super.onResume()
Log.e(TAG, "onResume: ");
}
override fun onPause(a) {
super.onPause()
Log.e(TAG, "onPause: ");
}
override fun onFinish(a) {
super.onFinish()
Log.e(TAG, "onFinish: ");
tvCountDownTime.text = "The countdown is over."
}
override fun onCancel(a) {
super.onCancel()
Log.e(TAG, "onCancel: ");
tvCountDownTime.text = "Countdown canceled."}})}override fun onDestroy(a) {
super.onDestroy()
mLTime.cancel()
}
}
Copy the code