1.下筆緣由
之前接觸過倒計時庐船,使用的是Android內置的倒計時方法CountDownTimer,這個確實挺好用的。之后我也自定義了一個倒計時的類闸溃。今天只是做一下記錄整吆。需求是希望能夠完整的觸碰到倒計時的各個狀態(tài)。從倒計時開始辉川,暫停表蝙,恢復到結束,這幾個狀態(tài)下我都能定義我的操作乓旗。
2.流程
3.Android自帶CountDownTimer實現(xiàn)
CountDownTimer其實是通過消息機制來實現(xiàn)倒計時的,想相信了解可以查看CountDownTimer類的源碼府蛇。
CountDownTimer使用起來很簡單拍霜,只需要實例化一個CountDownTimer(總時間, 時間間隔)對象净宵,在onTick(long millisUntilFinished)每隔n秒(也就是時間間隔)會回調一次方法onTick,如果沒有調用cancel(),那么倒計時結束的時候會調用onFinish()方法祖今。
開始倒計時:countDownTimer.start();
取消倒計時:countDownTimer.cancel();
public class MainActivity extends Activity implements OnClickListener
{
public static final int END = 0;
public static final int START = 1;
public static final int PASUSE = 2;
public static final int RESUME = 3;
private Button btnStart, btnCancel, btnPause, btnResume;
private CountDownTimer countDownTimer = null;
private int totalTime = 30;// 總時間
private int countNum = 1;//間隔時間妆距。每隔n秒會回調一次方法onTick
private int min = 1000;// 1秒
private int currentNum = -1;
private static int timerStatus = END;// 當前狀態(tài)
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("lgy", "==================onCreate");
btnStart = (Button) findViewById(R.id.cbtn_start);
btnStart.setOnClickListener(this);
btnCancel = (Button) findViewById(R.id.cbtn_cancel);
btnCancel.setOnClickListener(this);
btnPause = (Button) findViewById(R.id.cbtn_pause);
btnPause.setOnClickListener(this);
btnResume = (Button) findViewById(R.id.cbtn_resume);
btnResume.setOnClickListener(this);
}
@Override
protected void onDestroy()
{
super.onDestroy();
Log.i("lgy", "==================onDestroy");
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.cbtn_start:
initCount();
if (countDownTimer != null)
{
countDownTimer.cancel();
countDownTimer = null;
}
initCountDownTimer();
countDownTimer.start();
timerStatus = START;
break;
case R.id.cbtn_cancel:
if (countDownTimer != null)
{
countDownTimer.cancel();
countDownTimer = null;
}
timerStatus = END;
break;
case R.id.cbtn_pause:
if (timerStatus == START || timerStatus == PASUSE)
{
countDownTimer.cancel();
countDownTimer = null;
timerStatus = PASUSE;
}
break;
case R.id.cbtn_resume:
if (timerStatus == PASUSE)
{
if (currentNum > 0)
{
initCountDownTimer();
}
countDownTimer.start();
timerStatus = RESUME;
}
break;
}
}
/**
* Administrator
* 2017-1-9
*TODO 初始化數(shù)據(jù)
*/
private void initCount()
{
totalTime = 30;// 總時間
currentNum = totalTime;
timerStatus = END;// 當前狀態(tài)
}
/**
* Administrator
* 2017-1-9
*TODO 實例化CountDownTimer對象
*/
private void initCountDownTimer()
{
countDownTimer = new CountDownTimer(currentNum * min,
countNum * min)
{
@Override
public void onTick(long millisUntilFinished)
{
currentNum = (int) (millisUntilFinished / 1000);
Log.i("lgy", "==================onTick:"
+ millisUntilFinished / 1000);
}
@Override
public void onFinish()
{
Log.i("lgy", "==================onFinish");
}
};
}
}
4.自定義倒計時
首先先定義一個接口穷遂,是為了能在倒計時各個階段都能自定義我的操作:
/**
* Created by LGY on 2016/11/28.
*/
public interface CountDownCallback {
public void start();
public void pause();
public void resume();
public void cancel();
public void countDowning(long count);
public void end();
}
然后自定義倒計時控件:
/**
* Created by LGY on 2016/11/28.
*/
public class LCountDownTimer {
public static final int PREPARE = 0;
public static final int START = 1;
public static final int PASUSE = 2;
public static final int RESUME = 3;
private long countDownInterval = 1;//時間間隔
private int min = 1000;// 1秒
private long distination_total = min*60;//倒計時的總數(shù),這是不變的
private long timer_couting = min*60;//要被減少的倒計時
private static int timerStatus = LCountDownTimer.PREPARE;//當前狀態(tài)
private CountDownCallback callback = null;
private Timer timer;
private TimerTask timerTask;
public LCountDownTimer(CountDownCallback callback)
{
this.callback = callback;
}
/**
* start count down
* @throws Exception The counted number is less than zero!
*/
public void startTimer() throws Exception{
if (distination_total<=0)
{
throw new Exception("The counted number is less than zero!");
}
initTimerStatus();
timerStatus = LCountDownTimer.START;
if(callback!=null)
callback.start();
countTimer();
}
/**
* cancel count down
*/
public void cancelTimer(){
if (timer!=null)
{
timer.cancel();
timer = null;
}
if (timerTask!=null)
{
timerTask.cancel();
timerTask = null;
}
callback.cancel();
}
/**
* pause count down
*/
public void pauseTimer(){
if (timer==null)
return;
timer.cancel();
timerTask.cancel();
callback.pause();
timerStatus = LCountDownTimer.PASUSE;
}
/**
* resume count down
*/
public void resumeTimer(){
if (timer==null||timerStatus!=LCountDownTimer.PASUSE)
return;
countTimer();
callback.resume();
timerStatus = LCountDownTimer.RESUME;
}
/**
* initialize
*/
private void initTimerStatus(){
if (timer!=null)
{
timer.cancel();
timer = null;
}
if (timerTask!=null)
{
timerTask.cancel();
timerTask = null;
}
timerStatus = LCountDownTimer.PREPARE;
timer_couting = distination_total;
}
public int getTimerStatus()
{
return timerStatus;
}
/**
* set the total time
* @param timer_couting
*/
public void setTimer_couting(long timer_couting)
{
this.timer_couting = timer_couting*min;
this.distination_total = timer_couting*min;
}
/**
* Administrator
* 2017-1-9
*TODO set the countDown Interval
* @param countDownInterval
*/
public void setCountDownInterval(long countDownInterval)
{
this.countDownInterval = countDownInterval*min;
}
/**
* counting
*/
private void countTimer()
{
timer = new Timer();
timerTask = new TimerTask()
{
@Override
public void run() {
if(timer_couting<=0){
callback.end();
initTimerStatus();
return;
}
if(callback!=null)
callback.countDowning(timer_couting);
timer_couting -=countDownInterval;
}
};
timer.scheduleAtFixedRate(timerTask, 0, countDownInterval);
}
}
但是這個類有個問題就是娱据,當總時間能夠整除時間間隔的時候蚪黑,是沒什么問題的,但是如果不能整除中剩,那么就會多執(zhí)行幾秒忌穿。所以說使用的時候最好先判斷是不是能夠整除,本來是打算實現(xiàn)像CountDownTimer一樣實現(xiàn)可以配置時間間隔结啼,或許我就不應該讓時間間隔的參數(shù)可配置掠剑,直接寫死時間間隔是1s,然后直接在countDowning(long count)方法里寫我的邏輯。
例如郊愧,我們假設總時間是30秒澡腾,時間間隔是4秒,總時間明顯不能整除時間間隔糕珊,如果執(zhí)行上面的代碼动分,那么它會執(zhí)行到32秒。所以红选,可以直接在countDowning(long count)中定義邏輯澜公,這么做就不會多運行2秒了。
@Override
public void countDowning(long count) {
if (count!=0&&(((count/1000+2)%4)==0))
{
Log.i("lgy","count:"+count);
}
}
最后是調用這個自定義倒計時控件的例子:
public class MainActivity3 extends Activity implements CountDownCallback,View.OnClickListener {
//ui countdown
private Button btnStart,btnCancel,btnPause,btnResume;
private LCountDownTimer mLCountDownTimer = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnClickListener(this);
btnCancel = (Button) findViewById(R.id.btn_cancel);
btnCancel.setOnClickListener(this);
btnPause = (Button) findViewById(R.id.btn_pause);
btnPause.setOnClickListener(this);
btnResume = (Button) findViewById(R.id.btn_resume);
btnResume.setOnClickListener(this);
mLCountDownTimer = new LCountDownTimer(this);
mLCountDownTimer.setTimer_couting(30);
mLCountDownTimer.setCountDownInterval(1);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
try
{
mLCountDownTimer.startTimer();
} catch (Exception e)
{
e.printStackTrace();
}
break;
case R.id.btn_cancel:
mLCountDownTimer.cancelTimer();
break;
case R.id.btn_pause:
mLCountDownTimer.pauseTimer();
break;
case R.id.btn_resume:
mLCountDownTimer.resumeTimer();
break;
}
}
@Override
public void start() {
Log.i("lgy","start================");
}
@Override
public void pause() {
Log.i("lgy","pause================");
}
@Override
public void resume() {
Log.i("lgy","resume================");
}
@Override
public void cancel() {
Log.i("lgy","cancel================");
}
@Override
public void countDowning(long count) {
// if (count!=0&&(((count/1000+2)%4)==0))
// {
// Log.i("lgy","count:"+count);
// }
Log.i("lgy","count:"+count);
}
@Override
public void end()
{
Log.i("lgy","end================");
}
}
5.源碼地址
https://github.com/lgygg/CountDownTimer