Timer使用过程中出现的坑引发的思考

去年8月份用timer计时的一段程序在画UI的时候没有正常绘制,最近在查原因,发现踩了timer的坑,处理完后特此来记录一下。

Android中经常会在一段时间内重复去做一些事情,如开机向导的时候系统网络连接的比较慢,会耗时一会,这时候开机向导需要多次去检查系统网络有没有连接上,没有连接上才需要去在执行下面的流程。

类似于这种的重复多次执行一段程序的方法有很多种,总结一下目前可以实现的几种方法:

1、可以通过for循环加sleep来实现;

        //10s内检测是否满足某种条件
        for (int i = 0; i < 10; i++) {
            if (满足条件) {
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

 2、可以通过timer来实现

      Timer timer = new Timer();
      TimerTask task;
      final int PERIOD = 1000;
      int count = 0;


      task = new TimerTask() {

          @Override
          public void run() {
              // TODO Auto-generated method stub
              if(满足条件) 
              {
                  recycleTimer();
              }
              count++;
              if(count >= 10)
              {
                  recycleTimer();
              }
          }

          private void recycleTimer() 
          {
              count = 0;

              if(task != null) 
                  task.cancel();
              task = null;
              if(timer != null) 
                  timer.cancel();
              timer = null;
          }
      };
      timer.schedule(task, 0, PERIOD);

最近遇到一个比较奇怪的问题,android刚开机的时候在开机向导处,用timer计时去执行一个程序的时候,发现timer走到一半会假死,就不再执行后面的操作了,也是随机性的出来。

在网上查资料时,大家很多都推荐不要使用timer,timer有很多奇怪的问题,而且对系统时间比较敏感,尤其是系统时间发生变化的时候,timer就执行异常了。

我抓取了自己使用timer异常的情况,发现在开机的时候系统时间发生了跳变,由于系统在开机向导处系统会联网,时间会发生跳变,系统时间由默认的8:00多时间跳变到了14:00多时间,很大可能会导致timer发生问题,这个是timer设计上了缺陷。

最后打了一个补丁,启动timer计时执行的时候,同步执行了一个handler,如果handler检测到timer内部10s内还没有set退出循环的变量,就强行set此变量来退出循环。

现在大都推荐使用线程池ScheduledThreadPoolExecutor来替代timer。

3、使用计时器来实现

    LoadAccountPageCountDownTimer loadingTimer;
    class LoadAccountPageCountDownTimer extends CountDownTimer {

        public LoadAccountPageCountDownTimer(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
            // TODO Auto-generated constructor stub
        }


        @Override
        public void onFinish() {
            // TODO Auto-generated method stub
            Debugger.d(LogModel.GUIDE, "LoadAccountPageCountDownTimer on finish");
            if(满足什么条件) {

                return ;
            }
            //计时结束后,仍未满足条件执行后续流程
            ......

        }

        //每秒检查一次
        @Override
        public void onTick(long arg0) {
            // TODO Auto-generated method stub
            if (满足什么条件) {
                stopLoadAccountPageTimer();
            }
          }
        }

            private void startLoadAccountPageTimer() {
            if (loadingTimer != null) {
                loadingTimer.cancel();
            }
            if (loadingTimer == null) {
                loadingTimer = new LoadAccountPageCountDownTimer(10000, 1000);//10s中每隔1s检查一次
            }

            loadingTimer.start();
        }

        private void stopLoadAccountPageTimer() {
            if (loadingTimer != null) {
                loadingTimer.cancel();
                loadingTimer = null;
            }
        }

4、 通过handler来实现

如果涉及到UI的更新,可以用Handler来实现,每隔1s发送一次MSG来检查条件是否满足,如果满足条件,就不再发送MSG进行重复检查;或者超过10s就不再进行检查。

public abstract class BaseActivity extends Activity {

    private static DelayCheckHandler delayCheckHandler = null;
    private static final int MSG_CHECK_IS_OK = 0x00;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        delayCheckHandler = new DelayCheckHandler(this);
        delayCheckHandler.sendEmptyMessageDelayed(MSG_CHECK_IS_OK,1000);
    }

    int count = 0;
    private static class DelayCheckHandler extends Handler {

        WeakReference<BaseActivity> refActivity;
        private DelayCheckHandler(BaseActivity activity) {
            super(Looper.myLooper());
            this.refActivity = new WeakReference<BaseActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            if (refActivity == null || refActivity.get() == null) {
                return;
            }
            switch (msg.what) {
                case MSG_CHECK_IS_OK:
                    refActivity.get().checkIsOk();
                    break;
                default:
                    break;
            }
            super.handleMessage(msg);
        }
    }

    private void checkIsOk() {
        if (满足条件) {
            //TODO:更新UI
            return;
        }
        if (count >= 10) {
            return;
        }
        count++;
        delayCheckHandler.sendEmptyMessageDelayed(MSG_CHECK_IS_OK,1000);
    }
}

5、通过线程池来进行周期性执行某个任务

private ScheduledThreadPoolExecutor executorService; 
private IsNewModuleInsertRunnable runnable = null;
private count = 0;

//创建线程池,里面只有1个线程
executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
            private AtomicInteger atoInteger = new AtomicInteger(0);
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("check-loop-thread "+ atoInteger.getAndIncrement());
                return t;
            }
        });
runnable = new IsNewModuleInsertRunnable();

//首次延时1s,后面每隔1s执行一次runable线程        
executorService.scheduleWithFixedDelay(runnable, 1, 1, TimeUnit.SECONDS);

//注意线程的执行方法最好不要耗时超过线程执行的周期,否则会出现执行周期不是很准确问题
    private class IsNewModuleInsertRunnable implements Runnable {

        @Override
        public void run() {

            try {
                if (满足条件) {
                    //TODO:
                    stopThread();
                    return;
                }
               if (count >= 10) {
                   stopThread();
                   return;
                }
                count++;
            } catch (Exception e) {
                e.printStackTrace();
                L.d("exception !!!, " + e.getMessage());
            }
        }
    }

//停止正在执行的任务
private void stopThread() {
    executorService.shutdownNow();
}

微信公众号:一点微时光
欢迎关注我,一起学习,一起进步!

猜你喜欢

转载自blog.csdn.net/bukker/article/details/81303058