android消息处理机制-------Looper

本文将分析android内的looper,这个是用来封装消息循环和消息队列的一个类,handler其实可以看做是一个工具类,用来向消息队列中插入消息的。好比是WindowsAPISendMessage中的HANDLE,这个handle是窗口句柄。


  1. //Looper类分析  

  2. public class Looper {  

  3.    //static变量,判断是否打印调试信息。  

  4.     private static final boolean DEBUG = false;  

  5.     private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;  

  6.   

  7.     // sThreadLocal.get() will return null unless you've called prepare().  

  8. //线程本地存储功能的封装,TLSthread local storage,什么意思呢?因为存储要么在栈上,例如函数内定义的内部变量。要么在堆上,例如new或者malloc出来的东西  

  9. //但是现在的系统比如Linuxwindows都提供了线程本地存储空间,也就是这个存储空间是和线程相关的,一个线程内有一个内部存储空间,这样的话我把线程相关的东西就存储到  

  10. //这个线程的TLS中,就不用放在堆上而进行同步操作了。  

  11.     private static final ThreadLocal sThreadLocal = new ThreadLocal();  

  12. //消息队列,MessageQueue,看名字就知道是个queue..  

  13.     final MessageQueue mQueue;  

  14.     volatile boolean mRun;  

  15. //和本looper相关的那个线程,初始化为null  

  16.     Thread mThread;  

  17.     private Printer mLogging = null;  

  18. //static变量,代表一个UI Process(也可能是service吧,这里默认就是UI)的主线程  

  19.     private static Looper mMainLooper = null;  

  20.       

  21.      /** Initialize the current thread as a looper. 

  22.       * This gives you a chance to create handlers that then reference 

  23.       * this looper, before actually starting the loop. Be sure to call 

  24.       * {@link #loop()} after calling this method, and end it by calling 

  25.       * {@link #quit()}. 

  26.       */  

  27. //TLS中设上这个Looper对象的,如果这个线程已经设过了looper的话就会报错  

  28. //这说明,一个线程只能设一个looper  

  29.     public static final void prepare() {  

  30.         if (sThreadLocal.get() != null) {  

  31.             throw new RuntimeException("Only one Looper may be created per thread");  

  32.         }  

  33.         sThreadLocal.set(new Looper());  

  34.     }  

  35.       

  36.     /** Initialize the current thread as a looper, marking it as an application's main  

  37.      *  looper. The main looper for your application is created by the Android environment, 

  38.      *  so you should never need to call this function yourself. 

  39.      * {@link #prepare()} 

  40.      */  

  41.  //framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的  

  42. //      

  43.     public static final void prepareMainLooper() {  

  44.         prepare();  

  45.         setMainLooper(myLooper());  

  46. //判断主消息循环是否能退出....  

  47. //通过quit函数向looper发出退出申请  

  48.         if (Process.supportsProcesses()) {  

  49.             myLooper().mQueue.mQuitAllowed = false;  

  50.         }  

  51.     }  

  52.   

  53.     private synchronized static void setMainLooper(Looper looper) {  

  54.         mMainLooper = looper;  

  55.     }  

  56.       

  57.     /** Returns the application's main looper, which lives in the main thread of the application. 

  58.      */  

  59.     public synchronized static final Looper getMainLooper() {  

  60.         return mMainLooper;  

  61.     }  

  62.   

  63.     /** 

  64.      *  Run the message queue in this thread. Be sure to call 

  65.      * {@link #quit()} to end the loop. 

  66.      */  

  67. //消息循环,整个程序就在这里while了。  

  68. //这个是static函数喔!  

  69.     public static final void loop() {  

  70.         Looper me = myLooper();//从该线程中取出对应的looper对象  

  71.         MessageQueue queue = me.mQueue;//取消息队列对象...  

  72.         while (true) {  

  73.             Message msg = queue.next(); // might block取消息队列中的一个待处理消息..  

  74.             //if (!me.mRun) {//是否需要退出?mRun是个volatile变量,跨线程同步的,应该是有地方设置它。  

  75.             //    break;  

  76.             //}  

  77.             if (msg != null) {  

  78.                 if (msg.target == null) {  

  79.                     // No target is a magic identifier for the quit message.  

  80.                     return;  

  81.                 }  

  82.                 if (me.mLogging!= null) me.mLogging.println(  

  83.                         ">>>>> Dispatching to " + msg.target + " "  

  84.                         + msg.callback + ": " + msg.what  

  85.                         );  

  86.                 msg.target.dispatchMessage(msg);  

  87.                 if (me.mLogging!= null) me.mLogging.println(  

  88.                         "<<<<< Finished to    " + msg.target + " "  

  89.                         + msg.callback);  

  90.                 msg.recycle();  

  91.             }  

  92.         }  

  93.     }  

  94.   

  95.     /** 

  96.      * Return the Looper object associated with the current thread.  Returns 

  97.      * null if the calling thread is not associated with a Looper. 

  98.      */  

  99. //返回和线程相关的looper  

  100.     public static final Looper myLooper() {  

  101.         return (Looper)sThreadLocal.get();  

  102.     }  

  103.   

  104.     /** 

  105.      * Control logging of messages as they are processed by this Looper.  If 

  106.      * enabled, a log message will be written to <var>printer</var>  

  107.      * at the beginning and ending of each message dispatch, identifying the 

  108.      * target Handler and message contents. 

  109.       

  110.      * @param printer A Printer object that will receive log messages, or 

  111.      * null to disable message logging. 

  112.      */  

  113. //设置调试输出对象,looper循环的时候会打印相关信息,用来调试用最好了。  

  114.     public void setMessageLogging(Printer printer) {  

  115.         mLogging = printer;  

  116.     }  

  117.       

  118.     /** 

  119.      * Return the {@link MessageQueue} object associated with the current 

  120.      * thread.  This must be called from a thread running a Looper, or a 

  121.      * NullPointerException will be thrown. 

  122.      */  

  123.     public static final MessageQueue myQueue() {  

  124.         return myLooper().mQueue;  

  125.     }  

  126. //创建一个新的looper对象,  

  127. //内部分配一个消息队列,设置mRuntrue  

  128.     private Looper() {  

  129.         mQueue = new MessageQueue();  

  130.         mRun = true;  

  131.         mThread = Thread.currentThread();  

  132.     }  

  133.   

  134.     public void quit() {  

  135.         Message msg = Message.obtain();  

  136.         // NOTE: By enqueueing directly into the message queue, the  

  137.         // message is left with a null target.  This is how we know it is  

  138.         // a quit message.  

  139.         mQueue.enqueueMessage(msg, 0);  

  140.     }  

  141.   

  142.     /** 

  143.      * Return the Thread associated with this Looper. 

  144.      */  

  145.     public Thread getThread() {  

  146.         return mThread;  

  147.     }  

  148.     //后面就简单了,打印,异常定义等。  

  149.     public void dump(Printer pw, String prefix) {  

  150.         pw.println(prefix + this);  

  151.         pw.println(prefix + "mRun=" + mRun);  

  152.         pw.println(prefix + "mThread=" + mThread);  

  153.         pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));  

  154.         if (mQueue != null) {  

  155.             synchronized (mQueue) {  

  156.                 Message msg = mQueue.mMessages;  

  157.                 int n = 0;  

  158.                 while (msg != null) {  

  159.                     pw.println(prefix + "  Message " + n + ": " + msg);  

  160.                     n++;  

  161.                     msg = msg.next;  

  162.                 }  

  163.                 pw.println(prefix + "(Total messages: " + n + ")");  

  164.             }  

  165.         }  

  166.     }  

  167.   

  168.     public String toString() {  

  169.         return "Looper{"  

  170.             + Integer.toHexString(System.identityHashCode(this))  

  171.             "}";  

  172.     }  

  173.   

  174.     static class HandlerException extends Exception {  

  175.   

  176.         HandlerException(Message message, Throwable cause) {  

  177.             super(createMessage(cause), cause);  

  178.         }  

  179.   

  180.         static String createMessage(Throwable cause) {  

  181.             String causeMsg = cause.getMessage();  

  182.             if (causeMsg == null) {  

  183.                 causeMsg = cause.toString();  

  184.             }  

  185.             return causeMsg;  

  186.         }  

  187.     }  

  188. }  

那怎么往这个消息队列中发送消息呢??调用looperstatic函数myQueue可以获得消息队列,这样你就可用自己往里边插入消息了。不过这种方法比较麻烦,这个时候handler类就发挥作用了。先来看看handler的代码,就明白了。


  1. class Handler{  

  2. ..........  

  3. //handler默认构造函数  

  4. public Handler() {  

  5. //这个if是干嘛用的暂时还不明白,涉及到java的深层次的内容了应该  

  6.         if (FIND_POTENTIAL_LEAKS) {  

  7.             final Class<? extends Handler> klass = getClass();  

  8.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  

  9.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  

  10.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  

  11.                     klass.getCanonicalName());  

  12.             }  

  13.         }  

  14. //获取本线程的looper对象  

  15. //如果本线程还没有设置looper,这回抛异常  

  16.         mLooper = Looper.myLooper();  

  17.         if (mLooper == null) {  

  18.             throw new RuntimeException(  

  19.                 "Can't create handler inside thread that has not called Looper.prepare()");  

  20.         }  

  21. //无耻啊,直接把looperqueue和自己的queue搞成一个了  

  22. //这样的话,我通过handler的封装机制加消息的话,就相当于直接加到了looper的消息队列中去了  

  23.         mQueue = mLooper.mQueue;  

  24.         mCallback = null;  

  25.     }  

  26. //还有好几种构造函数,一个是带callback的,一个是带looper  

  27. //由外部设置looper  

  28.     public Handler(Looper looper) {  

  29.         mLooper = looper;  

  30.         mQueue = looper.mQueue;  

  31.         mCallback = null;  

  32.     }  

  33. // callback的,一个handler可以设置一个callback。如果有callback的话,  

  34. //凡是发到通过这个handler发送的消息,都有callback处理,相当于一个总的集中处理  

  35. //待会看dispatchMessage的时候再分析  

  36. public Handler(Looper looper, Callback callback) {  

  37.         mLooper = looper;  

  38.         mQueue = looper.mQueue;  

  39.         mCallback = callback;  

  40.     }  

  41. //  

  42. //通过handler发送消息  

  43. //调用了内部的一个sendMessageDelayed  

  44. public final boolean sendMessage(Message msg)  

  45.     {  

  46.         return sendMessageDelayed(msg, 0);  

  47.     }  

  48. //FT,又封装了一层,这回是调用sendMessageAtTime  

  49. //因为延时时间是基于当前调用时间的,所以需要获得绝对时间传递给sendMessageAtTime  

  50. public final boolean sendMessageDelayed(Message msg, long delayMillis)  

  51.     {  

  52.         if (delayMillis < 0) {  

  53.             delayMillis = 0;  

  54.         }  

  55.         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  

  56.     }  

  57.   

  58.   

  59. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  

  60.     {  

  61.         boolean sent = false;  

  62.         MessageQueue queue = mQueue;  

  63.         if (queue != null) {  

  64. //把消息的target设置为自己,然后加入到消息队列中  

  65. //对于队列这种数据结构来说,操作比较简单了  

  66.             msg.target = this;  

  67.             sent = queue.enqueueMessage(msg, uptimeMillis);  

  68.         }  

  69.         else {  

  70.             RuntimeException e = new RuntimeException(  

  71.                 this + " sendMessageAtTime() called with no mQueue");  

  72.             Log.w("Looper", e.getMessage(), e);  

  73.         }  

  74.         return sent;  

  75.     }  

  76. //还记得looper中的那个消息循环处理吗  

  77. //从消息队列中得到一个消息后,会调用它的targetdispatchMesage函数  

  78. //messagetarget已经设置为handler了,所以  

  79. //最后会转到handlermsg处理上来  

  80. //这里有个处理流程的问题  

  81. public void dispatchMessage(Message msg) {  

  82. //如果msg本身设置了callback,则直接交给这个callback处理了  

  83.         if (msg.callback != null) {  

  84.             handleCallback(msg);  

  85.         else {  

  86. //如果该handlercallback有的话,则交给这个callback处理了---相当于集中处理  

  87.           if (mCallback != null) {  

  88.                 if (mCallback.handleMessage(msg)) {  

  89.                     return;  

  90.                 }  

  91.            }  

  92. //否则交给派生处理,基类默认处理是什么都不干  

  93.             handleMessage(msg);  

  94.         }  

  95.     }  

  96. ..........  

  97. }  

 讲了这么多,该怎么创建和使用一个带消息循环的线程呢?


  1. //假设在onCreate中创建一个线程  

  2. //不花时间考虑代码的完整和严谨性了,以讲述原理为主。  

  3. ....  

  4.   

  5. ... onCreate(...){  

  6.   

  7. //难点是如何把android中的looperjavathread弄到一起去。  

  8. //而且还要把随时取得这个looper用来创建handler  

  9. //最简单的办法就是从Thread派生一个  

  10. class ThreadWithMessageHandle extends Thread{  

  11.   //重载run函数  

  12.   Looper myLooper = null;  

  13.   run(){  

  14.   Looper.prepare();//Looper设置到这个线程中  

  15.   myLooper = Looper.myLooper();  

  16.   Looper.loop();开启消息循环  

  17. }  

  18.   

  19.  ThreadWithMessageHandle  threadWithMgs = new ThreadWithMessageHandle();  

  20.  threadWithMsg.start();  

  21.  Looper looper = threadWithMsg.myLooper;//  

  22. //这里有个问题.threadWithMgs中的myLooper可能此时为空  

  23. //需要同步处理一下  

  24. //或者像API文档中的那样,把handler定义到ThreadWithMessageHandle到去。  

  25. //外线程获得这个handler的时候仍然要注意同步的问题,因为handler的创建是在run中的  

  26.  Handler threadHandler = new Handler(looper);  

  27.  threadHandler.sendMessage(...)  

  28. }  

  29.   

  30.   

  31. }  

  32.   

  33.   

  34.   

  35. ...  





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值