[Android][倒计时]

1.下笔缘由

之前接触过倒计时,使用的是Android内置的倒计时方法CountDownTimer,这个确实挺好用的。之后我也自定义了一个倒计时的类。今天只是做一下记录。需求是希望能够完整的触碰到倒计时的各个状态。从倒计时开始,暂停,恢复到结束,这几个状态下我都能定义我的操作。

2.流程

[Android][倒计时]_第1张图片
流程图

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

你可能感兴趣的:([Android][倒计时])