• 【转】Timer还是Handler


    在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler。然而个人认为:Handler在多个方面比Timer更为优秀,更推荐使用。

    一.易用性

    1. 可重复执行

    • Handler可以重复执行某个任务。
    • Timer若在某个任务执行/取消之后,再次执行则会抛出一个IllegalStateException异常。为了避免这个异常,需要重新创建一个Timer对象。

    2. 周期可调整

    若想要执行一个越来越快的定时任务,Handler可以做到,而Timer则消耗较大。

    • Handler
    private Handler handler = new Handler();
    
    int mDelayTime = 1000;
    private Runnable runnable = new Runnable() {
       public void run() {
          update();
          if (mDelayTime > 0) {
             handler.postDelayed(this,mDelayTime); 
             mDelayTime -= 100;
          }
       }
    };
    handler.postDelayed(runnable,1000);

    如以上例子,就可以实现对周期的动态调整。

    • Timer的scheduleAtFixedRate(TimerTask task, long delay, long period)只能执行固定周期的任务,所以不可以动态地调整周期。若想要动态调整,则需要在执行玩一个定时器任务后,再启动一个新的任务时设置新的时间。

    3. UI界面更新

    • Handler:在创建的时候可以指定所在的线程,一般在Activity中构建的,即主线程上,所以可以在回调方法中很方便的更新界面。
    • Timer:异步回调,所以必须借助Handler去更新界面,不方便。
      既然都得用Handler去更新界面了,为何不如把定时的功能也交给Handler去做呢?

    二.内存占比

    Timer比Handler更占内存。
    接下来的Demo例子通过两种方法循环地打印日志,然后通过MAT插件来查看这两个类所需要调用的对象所产生的占比。

    int mCount = 0;
    private void startTimer() {
    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
       @Override
       public void run() {
          Log.i("JKL", "" + mCount);
          mCount++;
          }
       }, 0, 200);
    }
    
    private void startHandler() {
    final Handler mHandler = new Handler();
    mHandler.post(new Runnable() {
       @Override
       public void run() {
          Log.i("JKL", "" + mCount);
          mCount++;
          mHandler.postDelayed(this, 200);
          }
       });
    }

    可以通过创建一个新的Android工程,在onCreate方法中调用以上startTimer或startHandler任意一个方法来测试。
    以下是MAT的测试结果。

    Timer相关对象的内存占比

    共有5个对象,占用1192B。

    Handler相关对象的内存占比

    我们可以看到上面有2个Handler,这时候你是否会疑惑呢?其实一个是我们生成的Handler,另外一个是Activity默认生成的,存在于ViewRootImp中,这涉及到ViewTree的知识,此处不便展开。
    不过我们可以知道,我们自己构建的Handler,最多也就只占64B。

    在使用Handler的时候,还需要用到Runnable,不过也只占了16B。
    所以,使用Handler的方式来作为定时器,最多也就是80B。


    以上可以得出结论,相比起Timer方式的定时器占用1192B,Handler的方式占用资源会小很多,只有1/60。

    所以Handler的方式比较节省内存。

    写到这里,想到一个点,Timer是创建一个线程去计数的,而Handler是在默认主线程运行的。假若Handler也用一个异步线程去运行,会不会耗很多资源呢?
    以下是测试代码:

    private void startHandler() {
       HandlerThread thread = new HandlerThread("Test");
       thread.start();
       final Handler mHandler = new Handler(thread.getLooper());
       mHandler.post(new Runnable() {
          @Override
          public void run() {
             Log.i("JKL", "" + mCount);
             mCount++;
             mHandler.postDelayed(this, 200);
             }
       });
    }

    以上用一个HandlerThread来启动一个新的线程。再看看内存占比:

    可以看到HandlerThread也只是占了96B的内存。


    综上所述,Handler内存占比低!而且低了不少。

    无论从易用性还是内存占比出发,Handler更胜一筹.

    版权声明:欢迎自由转载-非商用-非衍生-保持署名。作者:Benhero,博客地址:http://www.cnblogs.com/benhero/

  • 相关阅读:
    Go语言判断一个字节的高位大于四
    Golang封装一个加锁的Map工具包
    解决往服务器传文件时权限不够问题
    git 服务器同步代码错误 error: insufficient permission for adding an object to repository database .git/objects
    动态调用WebService
    sql的一些使用小技巧整理【不定期更新】
    【雅思】【口语】保持健康的活动
    【雅思】【口语】advertisement--buy sth.
    【雅思】【口语】Teacher
    【python】python_接口自动化测试框架
  • 原文地址:https://www.cnblogs.com/DarrenChan/p/5670072.html
Copyright © 2020-2023  润新知