• 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 }  
  • 相关阅读:
    mysql1193 HY000,MySQL ERROR 1193 (HY000): Unknown system variable 'validate_password_policy'
    MySQL服务正在启动或停止中,请稍候片刻后再试一次【解决方案】
    linux 服务器__MySQL远程连接 ERROR 2003 Can‘t connect to MySQL server (10060) 解决办法
    Linux Mysql8 安装教程
    Linux安装JDK完整步骤
    MySQL导入数据库1118错误解决方案[ERR] 1118 Row size too large (> 8126). Changing some columns to TEXT or BLOB
    死磕生菜 lettuce 间歇性发生 RedisCommandTimeoutException 的深层原理及解决方案
    Git: 将TAG推送到Gerrit中的特定分支
    不可不知的 MySQL 升级利器及 5.7 升级到 8.0 的注意事项
    kill 1和 0的区别
  • 原文地址:https://www.cnblogs.com/humanchan/p/3021034.html
Copyright © 2020-2023  润新知