Android中HandlerThread的使用及原理解析,handlerthread

來源:互聯網
上載者:User

Android中HandlerThread的使用及原理解析,handlerthread

關於Hanlder的基本使用可以參見博文《Android中Handler的使用》,如果想瞭解Handler、Looper、Thread等的相互關係以及內部實現原理可以參見博文《深入源碼解析Android中的Handler,Message,MessageQueue,Looper》。

Android中的API中對HandlerThread的描述是:
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
意思是HandlerThread類可以很方便地建立一個帶有looper的新線程。該looper可以被用來建立hanlder對象。需要注意的是start方法必須要調用。

先拋開HanlderThread,我們不用這個類看看怎麼使用Handler、Thread、Looper。

我們可以通過Looper.myLooper()方法得到當前線程所關聯的looper對象。在建立一個新線程的時候,初始情況下新線程是沒有關聯looper以及對應的訊息佇列MessageQueue的,對外表現出來就是在該新線程中調用Looper.myLooper()返回null。如果我們沒有意識到這一點,那麼我們在新線程中使用Handler肯能就會遇到問題。

假設為了在新線程中使用使用Handler,我們可能會寫出如下的代碼:

class TestThread extends Thread {      public Handler mHandler;      public void run() {          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };      }  }

但是在實際執行的時候會發現當運行到mHandler = new Handler()這一句時就會拋出異常:
Can’t create handler inside thread that has not called Looper.prepare()
之所以會拋出異常,可參見Handler建構函式的源碼。

拋出異常的原因是: 我們在建構函式中沒有傳遞Looper,這樣Hanlder在建構函式中就使用預設的looper,預設的looper是通過調用Looper.myLooper()得來的。當我們調用了Looper.prepare()之後,我們就會將looper關聯到當前線程中。因此只有在調用了Looper.prepare()這個方法之後,Looper.myLooper()才能得到looper對象。所以這裡提示我們要先調用Looper.prepare()方法才行。

為了能在新線程中正常建立使用Handler,我們將代碼改成如下所示:

class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = new Handler() {              public void handleMessage(Message msg) {                  //此處處理訊息              }          };          Looper.loop();      }}

我們在新線程的run方法中,首先調用了Looper.prepare()方法,這樣就將looper對象關聯到當前線程中了,然後執行new Handler(),在Hanlder的建構函式內部會調用Looper.myLooper()得到當前線程所關聯的looper對象。在建立完Hanlder對象之後,我們需要調用Looper.loop()方法讓訊息佇列迴圈起來。

通過上面的代碼我們就可以在一個新線程中建立並使用Handler對象了,但是問題是每次這麼寫感覺很羅嗦,不方便。為了讓能開發人員更方便地在新線程中建立並使用Handler,Android提供了HandlerThread這個類,HandlerThread是繼承自Thread類的。

使用HandlerThread的範例程式碼如下:

HandlerThread handlerThread = new HandlerThread("TestHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper()) {    public void handleMessage(Message msg) {        //此處處理訊息    };};

我們建立了HandlerThread之後需要先調用其start方法,調用start方法之後,run方法就會在HanlderThread線程中執行了。

HandlerThread這個類的run方法的源碼如下所示:

public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;}

我們可以看到,在該run方法中也是先調用了Looper.prepare()方法,然後通過Looper.myLooper()方法得到該線程所關聯的looper對象,最後會調用Looper.loop()方法讓訊息佇列迴圈起來。由此可以看出,HandlerThread的run方法主要就是將我們上面給出的正常情況下在新線程中建立Handler的代碼做了一些封裝而已。 在建立HandlerThread對象並調用其start方法之後,該HandlerThread線程就已經關聯了looper對象(通過Looper.prepare()方法關聯),並且該線程內部的訊息佇列迴圈了起來(通過Looper.loop()方法)。 最後我們只需要在建立Handler對象的時候通過handlerThread.getLooper()將handlerThread線程所關聯的looper對象傳遞給Handler的建構函式即可。 正如本文開頭API對HandlerThread所解釋的那樣: HandlerThread類可以很方便地建立一個帶有looper的新線程。該looper可以被用來建立hanlder對象。需要注意的是start方法必須要調用。

HandlerThread使用起來之所以感覺方便,是因為HandlerThread這個類在run方法內部對Looper做了一些工作(調用Looper.prepare()和Looper.loop()方法),這樣我們開發人員在使用的時候就不需要太多的與Looper打交道了,從而提升開發的便利性。HandlerThread並不是很高深的,只是對我們常見的開發流程做了封裝而已,因此我們不用HandlerThread而自己去實現也是可以的,具體用不用HandlerThread根據自己的喜好而定。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.