為什么要用HandlerThread,怎么用?

作為一個Android開發(fā),Handler機制是一定要了解的。在我面試過程中,發(fā)現(xiàn)很多人對Handler和Looper機制非常了解,對答如流,但是卻不知道何為HandlerThread。本文我們就來簡單聊一下它

HandlerThread是Thread的子類,它的作用很明確,文檔說的也很清楚

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幫我們創(chuàng)建好了Looper。
我們都知道,Android主線程的Looper是自動創(chuàng)建的,其他線程是沒有創(chuàng)建Looper的,需要我們自己創(chuàng)建。一般做法很簡單

@Override 
public void run() {
    Looper.prepare();
    Looper.loop();
}

prepare()loop()兩個方法不再贅述,我們先來看一個不用HandlerThread的例子:

Thread newThread = new Thread(new Runnable()
  {    
    @Override    
    public void run() {        
      Looper.prepare();        
      Looper.loop();    
    }
  });
newThread.start();
Handler handler = new Handler(newThread.getLooper());

相信不少人會用上面的方式創(chuàng)建一個異步線程的Handler,有沒有問題呢?肯定有。
newThread的looper是在這個線程運行之后創(chuàng)建的,所以,當執(zhí)行到Handler handler = new Handler(newThread.getLooper());的時候,newThread的looper可能還沒有創(chuàng)建好!
****這就是為什么我們需要HandlerThread,并不僅僅是因為它幫我們創(chuàng)建了一個looper,更重要的是它為我們處理了這個異步問題。****
來看下HandlerThread的實現(xiàn):

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

public Looper getLooper() {    
  if (!isAlive()) {        
    return null;    
  }        
  // If the thread has been started, wait until the looper has been created.    
  synchronized (this) {        
    while (isAlive() && mLooper == null) {            
      try {                
        wait();            
      } 
      catch (InterruptedException e) { }        
    }    
  }    
  return mLooper;
}

簡單的一個加鎖幫我們做了最重要的事情。

有人問我在run()方法里面,mTid開始賦值Process.myTid(),為什么后來又復制-1了呢?仔細想一下就有答案了,因為Looper.loop()是個死循環(huán)啊,執(zhí)行到mTid = -1的時候,就是looper退出的時候。


插一句,這個mTid是干嘛的?

/** * Returns the identifier of this thread. See Process.myTid(). */
public int getThreadId() {    
  return mTid;
}

Thread里面是沒有getThreadId()方法的,Process.myTid()方法定義如下:

/** * Returns the identifier of the calling thread, which be used with * {@link #setThreadPriority(int, int)}. */
public static final int myTid() {    
  return Libcore.os.gettid();
}

原來tid是修改線程優(yōu)先級、調(diào)度策略時用來做線程唯一標識的。那么在HandleThread中,把mTid置為-1是幾個意思?筆者的理解是,HandlerThread本身是為looper服務的,looper終止以后,線程也會馬上終止,為防止開發(fā)者錯誤使用,所以將mTid置為-1。


關于HandlerThread另外一個容易忽略的問題就是退出Looper。Looper通過quit()quitSafely()方法退出(記得,Looper.loop()之后是一個死循環(huán)),看看Looper的loop()方法的注釋

/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */
public static void loop()

Looper使用完畢執(zhí)行quit本身就是一件容易忽略的事情,如果放到HandlerThread中,更是容易忘得一干二凈。所以HandlerThread為我們提供了兩個相同的方法:

public boolean quit(){}
public boolean quitSafely(){}

****不過說到底,維護Looper的生命周期還是我們每個開發(fā)者自己的事情,HandlerThread只不過是封裝了一下,幫我們處理一個異步問題罷了。****

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容