爲何要用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.ide

意思就是說HandlerThread幫咱們建立好了Looper。
咱們都知道,Android主線程的Looper是自動建立的,其餘線程是沒有建立Looper的,須要咱們本身建立。通常作法很簡單oop

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

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

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

相信很多人會用上面的方式建立一個異步線程的Handler,有沒有問題呢?確定有。
newThread的looper是在這個線程運行以後建立的,因此,當執行到Handler handler = new Handler(newThread.getLooper());的時候,newThread的looper可能尚未建立好!
****這就是爲何咱們須要HandlerThread,並不單單是由於它幫咱們建立了一個looper,更重要的是它爲咱們處理了這個異步問題。****
來看下HandlerThread的實現:this

@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()是個死循環啊,執行到mTid = -1的時候,就是looper退出的時候。code


插一句,這個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是修改線程優先級、調度策略時用來作線程惟一標識的。那麼在HandleThread中,把mTid置爲-1是幾個意思?筆者的理解是,HandlerThread自己是爲looper服務的,looper終止之後,線程也會立刻終止,爲防止開發者錯誤使用,因此將mTid置爲-1。文檔


關於HandlerThread另一個容易忽略的問題就是退出Looper。Looper經過quit()quitSafely()方法退出(記得,Looper.loop()以後是一個死循環),看看Looper的loop()方法的註釋

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

Looper使用完畢執行quit自己就是一件容易忽略的事情,若是放到HandlerThread中,更是容易忘得一乾二淨。因此HandlerThread爲咱們提供了兩個相同的方法:

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

****不過說到底,維護Looper的生命週期仍是咱們每一個開發者本身的事情,HandlerThread只不過是封裝了一下,幫咱們處理一個異步問題罷了。****

相關文章
相關標籤/搜索