Android HandlerThread使用介紹以及源碼解析


摘要: 版權聲明:本文出自汪磊的博客,轉載請務必注明出處。


一、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 還是比較簡單理解的,好了,本篇到此為止,希望對你有幫助。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM