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. }  

相关内容