美文网首页安卓Android
Android 中常见的倒计时总结

Android 中常见的倒计时总结

作者: 因为我的心 | 来源:发表于2019-11-02 15:27 被阅读0次

    1. CountDownTimer 倒计时(谷歌官方推荐)

    • CountDownTimer是android中自带的倒计时类
      需要两个参数,一个是总计时的时间,一般验证码是60秒,就是60*1000。第二个参数是设置计时的速度,1000就是每秒一次。

    • 如果总长度是10秒,速度是1,那么就是10-9-8-7-6-5-4-3-2-1-0;

    • 如果总长度是10秒,速度是2,那么就是10-8-6-4-2-0;
      总时间是不变的,如果需要更精确的计时展现,就修改第二个参数。

    • 在创建对象的时候,需要重写onTick和onFinish的方法。
      onTick就是我们剩余的时间,需要将之转化成秒展示出来。
      在倒计时的过程中把按钮禁用。

    • 然后在onFinish倒计时结束的时候,按钮启用。

    • 最后通过.start启动倒计时。

      /**
       * 倒计时显示
       */
    CountDownTimer timer;
    private void countDown() {
    
     timer = new CountDownTimer(3000, 1000) {
          @Override
          public void onTick(long millisUntilFinished) {
             //每秒执行一次
             tvValue.setText( millisUntilFinished / 1000 + "s");
          }
           @Override
           public void onFinish() {
            // 最后执行完操作
              if (timer!=null){
                  timer.cancel();
                  timer = null;
              }
            }    
            }.start();
        }
    

    注意:

    在onTick或者onFinish的计时操作里定时跳转activity时,因为没有用timer.cancel()终止计时,会导致内存溢出等情况,在使用CountDownTimer时,在Activity或fragment生命周期结束时,调用timer.cancle()方法

    if (timer != null) {
        timer.cancel();
        timer = null;
        Intent intent=new Intent(MainActivity.this, Main2Activity.class);
      startActivity(intent);
    }
    

    2. 使用线程

    首先需要创建一个主线程,用来接收数据,改变UI

    private int time=10;
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:
                        setResult(RESULT_OK);
                        finish();
                        break;
                    case 4:
                        button4.setEnabled(false);
                        button4.setText("已发送(" + String.valueOf(time) + ")");
    
                        break;
                    case 5:
                        button4.setEnabled(true);
                        button4.setText("重新获取验证码");
    
                        time = 10;
                        break;
                    default:
                }
    
            }
        };
    

    运行一个子线程,由于子线程中无法更新UI,所以需要根据time,将当前状态发送到主线程中,在主线程中操作。

    当子线程执行的时候,按钮设置不可点击,并且将线程执行的结果一直发送给主线程,在主线程中动态显示倒计时。
    当time倒计时为0的时候,将time重置,按钮重新设置可点击。

     /**
         * 倒计时显示
         */
        private void countDown2() {
    
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        time--;
                        if (time <= 0) {
                            mHandler.sendEmptyMessage(5);
                        } else {
                            mHandler.sendEmptyMessage(4);
                            mHandler.postDelayed(this, 1000);
                        }
                    }
                };
                new Thread(runnable).start();
            
        }
    

    3. 使用Timer和TimerTask

    Timer类官方的解释是多个线程共享一个计时器,也就是当使用了方法二之后,再使用三、线程会比开辟出来一部分给当前的线程。

    假设总时间是10秒,点击按钮2,开始倒计时,同时点按钮3,时间会被瓜分掉。
    但是只调用一个线程操作是没问题的。

        /**
         * 倒计时显示3
         */
        int time = 10;
        private Timer timer = new Timer();
        private void countDown3() {
    
    
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
    
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            time--;
                            button4.setText("已发送(" + String.valueOf(time) + ")");
                            button4.setEnabled(false);
                            if (time <= 0) {
                                time = 10;
                                button4.setEnabled(true);
                                button4.setText("重新获取验证码");
                            }
                        }
                    });
                }
            };
           //调用方法
            timer.schedule(task, time, 1000);
    
        }
    

    注意:第三种方法,我忘记重新定义 time = 10;
    报出“java.lang.IllegalArgumentException: Negative delay.”这个错误,就是因为TimerTask中的time已经为 0 了,你再调用 time-- ,就会报出这个错误。

    4. 使用Handler倒计时(这个是不错的)

        //未开课中
        private Handler mHandler = new Handler();
        private MyRunnable mRunnable;
        private int downTime = 10;
    
    
        if (mRunnable == null) {
              mRunnable = new MyRunnable3();
               mHandler.postDelayed(mRunnable3, 0);
       }
    
     /**
         * 未上课计时实现
         */
        private class MyRunnable implements Runnable {
            @Override
            public void run() {
                --downTime;
                if (downTime == 0) {
                    UIUtils.MakeTextAndShow(mContext, "即将开始上课");
                    showLessonState();
                } else {
                    String value = UIUtils.formatTimeS(downTime);
                    tvTime.setText("还差\u2000" + value + "\u2000上课");
                }
                if (mHandler != null) {
                    mHandler.postDelayed(this, 1000);
                }
            }
        }
    

    5. ScheduledExecutorService

    此方式中 handler 功能与 timer 方式一致

        /**
         * ScheduledExecutorService 方式实现
         */
        private ScheduledExecutorService scheduled;
     
        private void scheduledExecutorService() {
            //初始化一个线程池大小为 1 的 ScheduledExecutorService
            scheduled = new ScheduledThreadPoolExecutor(1);
            mStart.setEnabled(false);//在发送数据的时候设置为不能点击
            mStart.setBackgroundColor(Color.GRAY);//背景色设为灰色
            scheduled.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    Message msg = mHandler.obtainMessage(0);
                    mHandler.sendMessage(msg);
                }
            }, 0, ONECE_TIME, TimeUnit.MILLISECONDS);
        }
    

    6. RxJava

    此方法通过 RxJava 的 interval 操作符来实现延时发送消息。接受消息的观察者将计时信息更新到 textview 中。此方法主要涉及到一些 RxJava 操作符以及线程切换,代码中也进行了注释。

    /**
         * RxJava 方式实现
         */
        private void rxJava() {
            final long count = TOTAL_TIME / 1000;
            Observable.interval(0, 1, TimeUnit.SECONDS)//设置0延迟,每隔一秒发送一条数据
                    .take((int) (count + 1)) //设置总共发送的次数
                    .map(new Func1<Long, Long>() {//long 值是从小到大,倒计时需要将值倒置
                        @Override
                        public Long call(Long aLong) {
                            return count - aLong; 
                        }
                    })
                    .subscribeOn(Schedulers.computation())
                    // doOnSubscribe 执行线程由下游逻辑最近的 subscribeOn() 控制,下游没有 subscribeOn() 则跟Subscriber 在同一线程执行
                    //执行计时任务前先将 button 设置为不可点击
                    .doOnSubscribe(new Action0() { 
                        @Override
                        public void call() { 
                            mStart.setEnabled(false);//在发送数据的时候设置为不能点击
                            mStart.setBackgroundColor(Color.GRAY);//背景色设为灰色
                        }
                    })
                    .observeOn(AndroidSchedulers.mainThread())//操作UI主要在UI线程
                    .subscribe(new Subscriber<Long>() {
                        @Override
                        public void onCompleted() {
                            mTvValue.setText(getResources().getString(R.string.done));
                            mStart.setEnabled(true);
                            mStart.setBackgroundColor(Color.parseColor("#f97e7e"));
                        }
     
                        @Override
                        public void onError(Throwable e) {
                            e.printStackTrace();
                        }
     
                        @Override
                        public void onNext(Long aLong) { //接收到一条就是会操作一次UI
                            String value = String.valueOf(aLong);
                            mTvValue.setText(value);
                        }
                    });
        }
    

    相关文章

      网友评论

        本文标题:Android 中常见的倒计时总结

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