导航

Android中HandlerThread类的解释

Posted on 2013-04-14 21:29  ChanHuman  阅读(282)  评论(0编辑  收藏  举报
 

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 }