定時任務 Handler vs Timer

前言

Android開發過程中,經常需要執行一些短週期的定時任務,這時候有兩個選擇Timer或者Handler。很多朋友都會爲選擇哪種方案最優而猶豫爲難,今天我們做一下比較,希望對各位以後開發都有一定的參考價值。(也是自己在網上優秀資料學習的一些整理吧,轉自博客園,作者:Benhero,博客地址:http://www.cnblogs.com/benhero/

一.易用性

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更勝一籌.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章