前言
原生的倒計時功能比較簡單,沒有暫停和重新開始計時功能誉结,所以仿照原生的CountDownTimer做一個更好用的倒計時功能董虱。
自定義類
public class LCountDownTimer {
/**
* 時間店煞,即開始的時間,通俗來說就是倒計時總時間
*/
private long mMillisInFuture;
/**
* 布爾值诵原,表示計時器是否被取消
* 只有調(diào)用cancel時才被設(shè)置為true
*/
private boolean mCancelled = false;
/**
* 用戶接收回調(diào)的時間間隔英妓,一般是1秒
*/
private long mCountdownInterval;
/**
* 記錄暫停時候的時間
*/
private long mStopTimeInFuture;
/**
* mas.what值
*/
private static final int MSG = 520;
/**
* 暫停時,當(dāng)時剩余時間
*/
private long mCurrentMillisLeft;
/**
* 是否暫停
* 只有當(dāng)調(diào)用pause時皮假,才設(shè)置為true
*/
private boolean mPause = false;
/**
* 監(jiān)聽listener
*/
private TimerListener mCountDownListener;
/**
* 是否創(chuàng)建開始
*/
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();
}
}
}
/**
* 按一下暫停惹资,再按一下繼續(xù)倒計時
*/
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();
}
}
}
}
/**
* 恢復(fù)暫停贺纲,開始
*/
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;
}
//剩余毫秒數(shù)
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執(zhí)行的時間
// 打印這個delay時間猴誊,大概是997毫秒
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
// 特殊情況:用戶的onTick方法花費的時間比interval長潦刃,那么直接跳轉(zhuǎn)到下一次interval
// 注意,在onTick回調(diào)的方法中懈叹,不要做些耗時的操作
boolean isWhile = false;
while (delay < 0){
delay += mCountdownInterval;
isWhile = true;
}
if (isWhile){
}
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
/**
* 設(shè)置倒計時總時間
* @param millisInFuture 毫秒值
*/
public void setMillisInFuture(long millisInFuture) {
long total = millisInFuture + 20;
this.mMillisInFuture = total;
}
/**
* 設(shè)置倒計時間隔值
* @param countdownInterval 間隔乖杠,一般設(shè)置為1000毫秒
*/
public void setCountdownInterval(long countdownInterval) {
this.mCountdownInterval = countdownInterval;
}
/**
* 設(shè)置倒計時監(jiān)聽
* @param countDownListener listener
*/
public void setCountDownListener(TimerListener countDownListener) {
this.mCountDownListener = countDownListener;
}
}
用到的抽象類:
public abstract class TimerListener {
/**
* 當(dāng)?shù)褂嫊r開始
*/
public void onStart(){
}
/**
* 當(dāng)?shù)褂嫊r恢復(fù)暫停
*/
public void onResume(){
}
/**
* 當(dāng)?shù)褂嫊r暫停
*/
public void onPause(){
}
/**
* 當(dāng)?shù)褂嫊r結(jié)束
*/
public void onFinish(){
}
/**
* 當(dāng)?shù)褂嫊r取消
*/
public void onCancel(){
}
/**倒計時進(jìn)行中
* @param millisUntilFinished 剩余時間
*/
public abstract void onTick(long millisUntilFinished);
}
使用示例
使用比較簡單,這里做個簡單的 demo澄成。
class CountDownActivity: AppCompatActivity(R.layout.activity_countdown) {
//初始化倒計時相關(guān)
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()
}
//時間的監(jiān)聽
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 = "倒計時結(jié)束"
}
override fun onCancel() {
super.onCancel()
Log.e(TAG, "onCancel: ");
tvCountDownTime.text = "倒計時取消"
}
})
}
override fun onDestroy() {
super.onDestroy()
mLTime.cancel()
}
}