歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android中HandlerThread類的解析

Android應用中的消息循環由Looper和Handler配合完成,Looper類用於封裝消息循環,類中有個MessageQueue消息隊列;Handler類封裝了消息投遞和消息處理等功能。

系統默認情況下只有主線程(即UI線程)綁定Looper對象,因此在主線程中可以直接創建Handler的實例,但是在子線程中就不能直接new出Handler的實例了,因為子線程默認並沒有Looper對象,此時會拋出RuntimeException異常:

浏覽下Handler的默認構造函數就一目了然了:

  1. public Handler() {  
  2.     if (FIND_POTENTIAL_LEAKS) {  
  3.         final Class<? extends Handler> klass = getClass();  
  4.         if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  5.                 (klass.getModifiers() & Modifier.STATIC) == 0) {  
  6.             Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  7.                 klass.getCanonicalName());  
  8.         }  
  9.     }  
  10.   
  11.     mLooper = Looper.myLooper();  
  12.     if (mLooper == null) {  
  13.         throw new RuntimeException(  
  14.             "Can't create handler inside thread that has not called Looper.prepare()");  
  15.     }  
  16.     mQueue = mLooper.mQueue;  
  17.     mCallback = null;  
  18. }  

如果需要在子線程中使用Handler類,首先需要創建Looper類實例,這時可以通過Looper.prepare()和Looper.loop()函數來實現的。閱讀Framework層源碼發現,Android為我們提供了一個HandlerThread類,該類繼承Thread類,並使用上面兩個函數創建Looper對象,而且使用wait/notifyAll解決了多線程中子線程1獲取子線程2的Looper對象為空的問題。HandlerThread類完整代碼如下:

  1. /** 
  2.  * Handy class for starting a new thread that has a looper. The looper can then 
  3.  * be used to create handler classes. Note that start() must still be called. 
  4.  */  
  5. public class HandlerThread extends Thread {  
  6.       
  7.     private int mPriority; // 線程優先級   
  8.       
  9.     private int mTid = -1; // 線程ID   
  10.       
  11.     private Looper mLooper; // 我們需要的Looper對象   
  12.   
  13.     public HandlerThread(String name) {  
  14.         super(name);  
  15.         mPriority = Process.THREAD_PRIORITY_DEFAULT;  
  16.     }  
  17.   
  18.     /** 
  19.      * Constructs a HandlerThread. 
  20.      *  
  21.      * @param name 
  22.      * @param priority 
  23.      *            The priority to run the thread at. The value supplied must be 
  24.      *            from {@link android.os.Process} and not from java.lang.Thread. 
  25.      */  
  26.     public HandlerThread(String name, int priority) {  
  27.         super(name);  
  28.         mPriority = priority;  
  29.     }  
  30.   
  31.     /** 
  32.      * 在Looper.loop()之前執行動作的回調函數 
  33.      */  
  34.     protected void onLooperPrepared() {  
  35.     }  
  36.   
  37.     public void run() {  
  38.         mTid = Process.myTid();  
  39.         Looper.prepare(); // 創建本線程的Looper對象   
  40.           
  41.         synchronized (this) {  
  42.             mLooper = Looper.myLooper();  
  43.             notifyAll(); //通知所有等待該線程Looper對象的其他子線程,本線程的Looper對象已就緒   
  44.         }  
  45.           
  46.         Process.setThreadPriority(mPriority);  
  47.         onLooperPrepared(); //回調函數   
  48.           
  49.         Looper.loop(); //開始消息隊列循環   
  50.         mTid = -1;  
  51.     }  
  52.   
  53.     /** 
  54.      * This method returns the Looper associated with this thread. If this 
  55.      * thread not been started or for any reason is isAlive() returns false, 
  56.      * this method will return null. If this thread has been started, this 
  57.      * method will block until the looper has been initialized. 
  58.      *  
  59.      * @return The looper. 
  60.      */  
  61.     public Looper getLooper() {  
  62.         if (!isAlive()) {  
  63.             return null;  
  64.         }  
  65.   
  66.         // If the thread has been started, wait until the looper has been   
  67.         // created.   
  68.         synchronized (this) {  
  69.             while (isAlive() && mLooper == null) {  
  70.                 try {  
  71.                     wait(); //Looper對象未創建好,等待   
  72.                 } catch (InterruptedException e) {  
  73.                 }  
  74.             }  
  75.         }  
  76.         return mLooper;  
  77.     }  
  78.   
  79.     /** 
  80.      * Ask the currently running looper to quit. If the thread has not been 
  81.      * started or has finished (that is if {@link #getLooper} returns null), 
  82.      * then false is returned. Otherwise the looper is asked to quit and true is 
  83.      * returned. 
  84.      */  
  85.     public boolean quit() {  
  86.         Looper looper = getLooper();  
  87.         if (looper != null) {  
  88.             looper.quit();  
  89.             return true;  
  90.         }  
  91.         return false;  
  92.     }  
  93.   
  94.     /** 
  95.      * Returns the identifier of this thread. See Process.myTid(). 
  96.      */  
  97.     public int getThreadId() {  
  98.         return mTid;  
  99.     }  
  100. }  
Copyright © Linux教程網 All Rights Reserved