HandlerThread

原文:http:\/\/givemepass-blog.logdown.com\/posts\/296790-how-to-use-handlerthread

Android高效能執行緒

http:\/\/blog.maxkit.com.tw\/2016\/03\/handlerthread-in-android.html

Handler的運作原理,預設在Main Thread(UI Thread)

  • 如果要多開Thread來使用Hanlder,則必須自行控制Looper,相對上比較麻煩, 因此Android開發了HandlerThread讓你能夠方便操作。

  • 如果在android.os.Handler裡需要執行一些非常耗時的任務,就應該把Handler放到HandlerThread裡面執行(或者在Handler裡新開線程執行),而不應該直接在UI線程中執行,否則會增加出現ANR(Application Not Responding)的可能 。

HandlerThread整合了Thread、Looper和MessageQueue。啟動方式跟Thread相同。

HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();

Handler mHandler = new Hanlder(handlerThread.getLooper()){
    public void handleMessage(Message msg){
        super.handleMessage(msg);
        switch(msg.what){
        case 1:
            Logger.e("message receive");
        case 2:
            Logger.e("message receive");
        break;
        }
    }
}

public void taskOne() {
   mHandler.sendEmptyMessage(1);
}
public void taskTwo() {
   mHandler.sendEmptyMessage(2);
}
//或者

new Hanlder(handlerThread.getLooper()).post(new Runnable(){
    public void run(){
       //長時間任務1

       //長時間任務2

    }
});

上面的例子一旦執行, 除非你手動停止, 否則該thread會一直等待執行下去。

Handler 的存取能夠透過 HandlerThread 的子類別,設定為私有的,並確保 Looper 不可被存取,由該子類別提供給客戶端公用的存取 method。

public class MyHandlerThread extends HandlerThread { 
    private Handler mHandler;
    public MyHandlerThread() {
       super("MyHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
    } 

    @Override protected void onLooperPrepared() {
       super.onLooperPrepared(); 
       mHandler = new Handler(getLooper()) {
          @Override public void handleMessage(Message msg) {
             switch(msg.what) {
                case 1: 
                   // Handle message
                   break;
                case 2:
                   // Handle message break;
             }
           }
        };
     }
     public void publishedMethod1() { 
        mHandler.sendEmptyMessage(1);
     }
     public void publishedMethod2() {
        mHandler.sendEmptyMessage(2);
     }
}

利用Handler丟Message,透過Looper循序message發送,因此確保是執行緒安全的,但是相對缺點就是效率會下降。

HandlerThread的生命周期

  • Creation(建立): HandlerThread建構子有名稱, 或者名稱跟優先權
HandlerThread(String name)
HandlerThread(String name, int priority)
  • Execution(執行): 代表已經被start了, 隨時可以接受訊息到來。
  • Reset(重設): 你可以將Queue內的訊息清空, 除了已經送出去的Message或者正在執行的Message
mHandlerThread.removeCallbackAndMessages(null);
  • Termination(終止):
   public void stopHandlerThread(HandlerThread handlerThread){
       handlerThread.quit();
       handlerThread.interrupt();
   }
   //或者直接在handler上面

   handler.post(new Runnable(){
       public void run(){
           Looper.myLooper.quit();
       }
   });

HandlerThread確保是循序且執行緒安全的, 有人會覺得既然如此, Thread也可以達成這樣的需求,

是沒錯, 不過這樣變成你必須在程式碼內同時寫在同一個Thread內。

   new Thread(new Runnable(){
       public void run(){
           //task 1

           //task 2

           //task 3
       }
   });

也許有人會反駁, 那麼我可以寫在另外一個Thread內啊!

也沒錯, 但是相對的你就必須開多個Thread, 這樣一來就沒有確保執行緒安全了!

  new Thread(new Runnable(){
       public void run(){
           //task 1
       }
  });
  new Thread(new Runnable(){
       public void run(){
           //task 2
       }
  });
  new Thread(new Runnable(){
       public void run(){
           //task 3
       }
  });

如上述例子 task1,task2,task3有存取到共同的資料結構, 則可能會產生concurrent的問題。

那也許會有人說(還真多人XD), 只要確保資料結構是同步的即可。

還是對的! 但是那個資料結構就必須使用Concurrent系列的, 或者自行實作synchronized,

效能相對會下降, 程式碼也會變得比較複雜。

不過使用方法必須對應到使用情境, 也不一定就是HandlerThread是萬用解藥。

沿伸閱讀:

http:\/\/codetheory.in\/android-handlers-runnables-loopers-messagequeue-handlerthread\/

results matching ""

    No results matching ""