1.下笔缘由
之前接触过倒计时,使用的是Android内置的倒计时方法CountDownTimer,这个确实挺好用的。之后我也自定义了一个倒计时的类。今天只是做一下记录。需求是希望能够完整的触碰到倒计时的各个状态。从倒计时开始,暂停,恢复到结束,这几个状态下我都能定义我的操作。
2.流程
3.Android自带CountDownTimer实现
CountDownTimer其实是通过消息机制来实现倒计时的,想相信了解可以查看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;// 当前状态
@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 初始化数据
*/
private void initCount()
{
totalTime = 30;// 总时间
currentNum = totalTime;
timerStatus = END;// 当前状态
}
/**
* 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;//倒计时的总数,这是不变的
private long timer_couting = min*60;//要被减少的倒计时
private static int timerStatus = LCountDownTimer.PREPARE;//当前状态
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);
}
}
但是这个类有个问题就是,当总时间能够整除时间间隔的时候,是没什么问题的,但是如果不能整除,那么就会多执行几秒。所以说使用的时候最好先判断是不是能够整除,本来是打算实现像CountDownTimer一样实现可以配置时间间隔,或许我就不应该让时间间隔的参数可配置,直接写死时间间隔是1s,然后直接在countDowning(long count)方法里写我的逻辑。
例如,我们假设总时间是30秒,时间间隔是4秒,总时间明显不能整除时间间隔,如果执行上面的代码,那么它会执行到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
6.参考文章
http://blog.csdn.net/arjinmc/article/details/47775995