美文网首页
[Android][倒计时]

[Android][倒计时]

作者: lgy_gg | 来源:发表于2017-01-10 09:35 被阅读0次

    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

    相关文章

      网友评论

          本文标题:[Android][倒计时]

          本文链接:https://www.haomeiwen.com/subject/frhhbttx.html