摘要: 版權聲明:本文出自汪磊的博客,轉載請務必注明出處。
一、HandlerThread的介紹及使用舉例
HandlerThread是什么鬼?其本質就是一個線程,但是HandlerThread在啟動的時候會幫我們准備好一個Looper,並供外界使用,說白了就是使我們在子線程中更方便的使用Handler,比如沒有HandlerThread我們要在子線程使用Handler,寫法如下:
1 private Handler mHandler; 2
3 @Override 4 public void run() { 5 super.run(); 6
7 Looper.prepare(); 8
9 mHandler = new Handler(){ 10
11 @Override 12 public void handleMessage(Message msg) { 13
14 } 15 }; 16
17 Looper.loop(); 18 }
有了HandlerThread就不用我們自己管理Looper了,至於為什么分析源碼的時候就明白了。
HandlerThread使用簡單介紹:
首先我們要初始化HandlerThread然后調用其start方法,也就是開啟線程:
1 mHandlerThread = new HandlerThread("mHandlerThread");//這里的mHandlerThread其實就是線程的名字 2 mHandlerThread.start();
接下來初始化一個Handler並且將mHandlerThread中的Looper作為構造函數參數傳遞給Handler:
1 mHandler = new Handler(mHandlerThread.getLooper())
這樣就保證了Hnadler運行在子線程。並且需要在適合的時機調用HandlerThread的quit方法或quitSafely方法,如Activity銷毀的時候:
1 @Override 2 protected void onDestroy() { 3 // 4 super.onDestroy(); 5 //釋放資源
6 mHandlerThread.quit(); 7 }
quit()與quitSafely()方法比較(這里只說一些結論,源碼可以自己查看):
相同點:
調用之后MessageQueue消息隊列均不在接受新的消息加入隊列。
不同點:
quit方法把MessageQueue消息池中所有的消息全部清空。quitSafely方法只會清空MessageQueue消息池中所有的延遲消息(延遲消息是指通過sendMessageDelayed或postDelayed等方法發送的消息),非延遲消息則不清除繼續派發出去讓Handler去處理。
接下來我們完整看一下HandlerThread例子源碼:
1 public class MainActivity extends Activity { 2
3 private HandlerThread mHandlerThread; 4 private Handler mHandler; 5 private boolean flag; 6 // 7
8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 setContentView(R.layout.activity_main); 12
13 mHandlerThread = new HandlerThread("mHandlerThread"); 14 mHandlerThread.start(); 15
16 mHandler = new Handler(mHandlerThread.getLooper()) { 17
18 @Override 19 public void handleMessage(Message msg) { 20 // 21 try { 22 Thread.sleep(2000); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26
27 if(flag){ 28 Log.i("HandlerThread", "更新:"+new Random().nextInt(1000)); 29 } 30 mHandler.sendEmptyMessage(1); 31 } 32 }; 33
34 } 35
36 @Override 37 protected void onResume() { 38 // 39 super.onResume(); 40 flag = true; 41 mHandler.sendEmptyMessage(1); 42 } 43
44 @Override 45 protected void onPause() { 46 // 47 super.onPause(); 48 flag = false; 49 } 50
51 @Override 52 protected void onDestroy() { 53 // 54 super.onDestroy(); 55 //釋放資源
56 mHandlerThread.quit(); 57 } 58 }
運行程序就會在控制台看到每隔兩秒有Log打出。至於HandlerThrea的使用就到此為止了,看懂上面小例子就差不多了。
二、HandlerThread的源碼分析
HandlerThread源碼非常簡短,出去注釋不到100行,這里就直接全部貼出來了:
1 public class HandlerThread extends Thread { 2 int mPriority; 3 int mTid = -1; 4 Looper mLooper; 5
6 public HandlerThread(String name) { 7 super(name); 8 mPriority = Process.THREAD_PRIORITY_DEFAULT; 9 } 10
11 /**
12 * Constructs a HandlerThread. 13 * @param name 14 * @param priority The priority to run the thread at. The value supplied must be from 15 * {@link android.os.Process} and not from java.lang.Thread. 16 */
17 public HandlerThread(String name, int priority) { 18 super(name); 19 mPriority = priority; 20 } 21
22 /**
23 * Call back method that can be explicitly overridden if needed to execute some 24 * setup before Looper loops. 25 */
26 protected void onLooperPrepared() { 27 } 28
29 @Override 30 public void run() { 31 mTid = Process.myTid(); 32 Looper.prepare(); 33 synchronized (this) { 34 mLooper = Looper.myLooper(); 35 notifyAll(); 36 } 37 Process.setThreadPriority(mPriority); 38 onLooperPrepared(); 39 Looper.loop(); 40 mTid = -1; 41 } 42
43 /**
44 * This method returns the Looper associated with this thread. If this thread not been started 45 * or for any reason is isAlive() returns false, this method will return null. If this thread 46 * has been started, this method will block until the looper has been initialized. 47 * @return The looper. 48 */
49 public Looper getLooper() { 50 if (!isAlive()) { 51 return null; 52 } 53
54 // If the thread has been started, wait until the looper has been created.
55 synchronized (this) { 56 while (isAlive() && mLooper == null) { 57 try { 58 wait(); 59 } catch (InterruptedException e) { 60 } 61 } 62 } 63 return mLooper; 64 } 65
66
67 public boolean quit() { 68 Looper looper = getLooper(); 69 if (looper != null) { 70 looper.quit(); 71 return true; 72 } 73 return false; 74 } 75
76
77 public boolean quitSafely() { 78 Looper looper = getLooper(); 79 if (looper != null) { 80 looper.quitSafely(); 81 return true; 82 } 83 return false; 84 } 85
86 /**
87 * Returns the identifier of this thread. See Process.myTid(). 88 */
89 public int getThreadId() { 90 return mTid; 91 } 92 }
看第一行就知道了其本質就是一個線程。
6-9行以及17-20行構造函數,也很簡單,就是初始化的時候我們可以定義線程名字,還可以傳入線程優先級。
初始化完成,緊接着調用start()開發線程就會執行run方法邏輯。
30-41行代碼,最重要的就是調用Looper.prepare()以及Looper.loop()方法為我們在子線程准備好一個Looper。並且用變量mLooper記錄,調用getLooper()方法的時候返回。
但是,細心的你肯定發現run()方法中有個notifyAll(),getLooper()中有個wait()為什么要加這些鳥玩意?
大家發現沒在HandlerThread 例子中Handler的創建是在主線程完成的,創建的時候需要調用HandlerThread的getLooper()獲取mLooper作為參數傳遞給Handler的構造函數,而Looper的創建是在子線程中創建的,這里就有線程同步問題了,比如我們調用getLooper()的時候HandlerThread中run()方法還沒執行完,mLooper變量還未賦值,此時就執行了wait()等待邏輯,一直等到run()方法中mLooper被賦值,之后立即執行notifyAll(),然后getLooper()就可以正確返回mLooper了。
明白了吧,不明的話這里需要花些時間好好理解下,好了源碼主要部分就分析完了,看到這里相信你對HandlerThread有了一定的了解了。
HandlerThread 還是比較簡單理解的,好了,本篇到此為止,希望對你有幫助。