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只不過是封裝了一下,幫咱們處理一個異步問題罷了。****