`
zyc1006
  • 浏览: 133833 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Android Handler Looper

 
阅读更多

第一次接触android应用程序(这里指的是JAVA层的UI程序,也难怪了,Google放出的API就只支持JAVA应用程序了),很难搞明白内部是如何实现的。但是,从原理上分析,应该是有一个消息循环,一个消息队列,然后主线程不断得从消息队列中取得消息并处理之。

然而,google封装得太厉害了,所以一时半会还是搞不清楚到底是怎么做的。本文将分析android内的looper,这个是用来封装消息循环和消息队列的一个类,handler其实可以看做是一个工具类,用来向消息队列中插入消息的。好比是Windows API的SendMessage中的HANDLE,这个handle是窗口句柄。

 

  1. //Looper类分析  
  2. //没找到合适的分析代码的办法,只能这么来了。每个重要行的上面都会加上注释  
  3. //功能方面的代码会在代码前加上一段分析  
  4. public class Looper {  
  5.    //static变量,判断是否打印调试信息。  
  6.     private static final boolean DEBUG = false;  
  7.     private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;  
  8.   
  9.     // sThreadLocal.get() will return null unless you've called prepare().  
  10. //线程本地存储功能的封装,TLS,thread local storage,什么意思呢?因为存储要么在栈上,例如函数内定义的内部变量。要么在堆上,例如new或者malloc出来的东西  
  11. //但是现在的系统比如Linux和windows都提供了线程本地存储空间,也就是这个存储空间是和线程相关的,一个线程内有一个内部存储空间,这样的话我把线程相关的东西就存储到  
  12. //这个线程的TLS中,就不用放在堆上而进行同步操作了。  
  13.     private static final ThreadLocal sThreadLocal = new ThreadLocal();  
  14. //消息队列,MessageQueue,看名字就知道是个queue..  
  15.     final MessageQueue mQueue;  
  16.     volatile boolean mRun;  
  17. //和本looper相关的那个线程,初始化为null  
  18.     Thread mThread;  
  19.     private Printer mLogging = null;  
  20. //static变量,代表一个UI Process(也可能是service吧,这里默认就是UI)的主线程  
  21.     private static Looper mMainLooper = null;  
  22.       
  23.      /** Initialize the current thread as a looper. 
  24.       * This gives you a chance to create handlers that then reference 
  25.       * this looper, before actually starting the loop. Be sure to call 
  26.       * {@link #loop()} after calling this method, and end it by calling 
  27.       * {@link #quit()}. 
  28.       */  
  29. //往TLS中设上这个Looper对象的,如果这个线程已经设过了looper的话就会报错  
  30. //这说明,一个线程只能设一个looper  
  31.     public static final void prepare() {  
  32.         if (sThreadLocal.get() != null) {  
  33.             throw new RuntimeException("Only one Looper may be created per thread");  
  34.         }  
  35.         sThreadLocal.set(new Looper());  
  36.     }  
  37.       
  38.     /** Initialize the current thread as a looper, marking it as an application's main  
  39.      *  looper. The main looper for your application is created by the Android environment, 
  40.      *  so you should never need to call this function yourself. 
  41.      * {@link #prepare()} 
  42.      */  
  43.  //由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的  
  44. //      
  45.     public static final void prepareMainLooper() {  
  46.         prepare();  
  47.         setMainLooper(myLooper());  
  48. //判断主消息循环是否能退出....  
  49. //通过quit函数向looper发出退出申请  
  50.         if (Process.supportsProcesses()) {  
  51.             myLooper().mQueue.mQuitAllowed = false;  
  52.         }  
  53.     }  
  54.   
  55.     private synchronized static void setMainLooper(Looper looper) {  
  56.         mMainLooper = looper;  
  57.     }  
  58.       
  59.     /** Returns the application's main looper, which lives in the main thread of the application. 
  60.      */  
  61.     public synchronized static final Looper getMainLooper() {  
  62.         return mMainLooper;  
  63.     }  
  64.   
  65.     /** 
  66.      *  Run the message queue in this thread. Be sure to call 
  67.      * {@link #quit()} to end the loop. 
  68.      */  
  69. //消息循环,整个程序就在这里while了。  
  70. //这个是static函数喔!  
  71.     public static final void loop() {  
  72.         Looper me = myLooper();//从该线程中取出对应的looper对象  
  73.         MessageQueue queue = me.mQueue;//取消息队列对象...  
  74.         while (true) {  
  75.             Message msg = queue.next(); // might block取消息队列中的一个待处理消息..  
  76.             //if (!me.mRun) {//是否需要退出?mRun是个volatile变量,跨线程同步的,应该是有地方设置它。  
  77.             //    break;  
  78.             //}  
  79.             if (msg != null) {  
  80.                 if (msg.target == null) {  
  81.                     // No target is a magic identifier for the quit message.  
  82.                     return;  
  83.                 }  
  84.                 if (me.mLogging!= null) me.mLogging.println(  
  85.                         ">>>>> Dispatching to " + msg.target + " "  
  86.                         + msg.callback + ": " + msg.what  
  87.                         );  
  88.                 msg.target.dispatchMessage(msg);  
  89.                 if (me.mLogging!= null) me.mLogging.println(  
  90.                         "<<<<< Finished to    " + msg.target + " "  
  91.                         + msg.callback);  
  92.                 msg.recycle();  
  93.             }  
  94.         }  
  95.     }  
  96.   
  97.     /** 
  98.      * Return the Looper object associated with the current thread.  Returns 
  99.      * null if the calling thread is not associated with a Looper. 
  100.      */  
  101. //返回和线程相关的looper  
  102.     public static final Looper myLooper() {  
  103.         return (Looper)sThreadLocal.get();  
  104.     }  
  105.   
  106.     /** 
  107.      * Control logging of messages as they are processed by this Looper.  If 
  108.      * enabled, a log message will be written to <var>printer</var>  
  109.      * at the beginning and ending of each message dispatch, identifying the 
  110.      * target Handler and message contents. 
  111.      *  
  112.      * @param printer A Printer object that will receive log messages, or 
  113.      * null to disable message logging. 
  114.      */  
  115. //设置调试输出对象,looper循环的时候会打印相关信息,用来调试用最好了。  
  116.     public void setMessageLogging(Printer printer) {  
  117.         mLogging = printer;  
  118.     }  
  119.       
  120.     /** 
  121.      * Return the {@link MessageQueue} object associated with the current 
  122.      * thread.  This must be called from a thread running a Looper, or a 
  123.      * NullPointerException will be thrown. 
  124.      */  
  125.     public static final MessageQueue myQueue() {  
  126.         return myLooper().mQueue;  
  127.     }  
  128. //创建一个新的looper对象,  
  129. //内部分配一个消息队列,设置mRun为true  
  130.     private Looper() {  
  131.         mQueue = new MessageQueue();  
  132.         mRun = true;  
  133.         mThread = Thread.currentThread();  
  134.     }  
  135.   
  136.     public void quit() {  
  137.         Message msg = Message.obtain();  
  138.         // NOTE: By enqueueing directly into the message queue, the  
  139.         // message is left with a null target.  This is how we know it is  
  140.         // a quit message.  
  141.         mQueue.enqueueMessage(msg, 0);  
  142.     }  
  143.   
  144.     /** 
  145.      * Return the Thread associated with this Looper. 
  146.      */  
  147.     public Thread getThread() {  
  148.         return mThread;  
  149.     }  
  150.     //后面就简单了,打印,异常定义等。  
  151.     public void dump(Printer pw, String prefix) {  
  152.         pw.println(prefix + this);  
  153.         pw.println(prefix + "mRun=" + mRun);  
  154.         pw.println(prefix + "mThread=" + mThread);  
  155.         pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));  
  156.         if (mQueue != null) {  
  157.             synchronized (mQueue) {  
  158.                 Message msg = mQueue.mMessages;  
  159.                 int n = 0;  
  160.                 while (msg != null) {  
  161.                     pw.println(prefix + "  Message " + n + ": " + msg);  
  162.                     n++;  
  163.                     msg = msg.next;  
  164.                 }  
  165.                 pw.println(prefix + "(Total messages: " + n + ")");  
  166.             }  
  167.         }  
  168.     }  
  169.   
  170.     public String toString() {  
  171.         return "Looper{"  
  172.             + Integer.toHexString(System.identityHashCode(this))  
  173.             + "}";  
  174.     }  
  175.   
  176.     static class HandlerException extends Exception {  
  177.   
  178.         HandlerException(Message message, Throwable cause) {  
  179.             super(createMessage(cause), cause);  
  180.         }  
  181.   
  182.         static String createMessage(Throwable cause) {  
  183.             String causeMsg = cause.getMessage();  
  184.             if (causeMsg == null) {  
  185.                 causeMsg = cause.toString();  
  186.             }  
  187.             return causeMsg;  
  188.         }  
  189.     }  
  190. }  

 

那怎么往这个消息队列中发送消息呢??调用looper的static函数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. //无耻啊,直接把looper的queue和自己的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. //从消息队列中得到一个消息后,会调用它的target的dispatchMesage函数  
  78. //message的target已经设置为handler了,所以  
  79. //最后会转到handler的msg处理上来  
  80. //这里有个处理流程的问题  
  81. public void dispatchMessage(Message msg) {  
  82. //如果msg本身设置了callback,则直接交给这个callback处理了  
  83.         if (msg.callback != null) {  
  84.             handleCallback(msg);  
  85.         } else {  
  86. //如果该handler的callback有的话,则交给这个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中的looper和java的thread弄到一起去。  
  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. ...  

 

好了,handler和looper的分析就都这了,其实原理挺简单的。

分享到:
评论
1 楼 zhjxzhj 2011-08-19  
非常感谢  辛苦了

相关推荐

    Android Handler Looper Message 使用示例

    在主线程即UI线程外,新建一个Looper线程,并用Messenger和Handler来处理message和posted runnable。程序中,在负线程中默认加了一个3s的线程等来,来帮助理解sent message和post runnable之间的同步机制。所以在按...

    自定义Handler-Looper实现线程间通信

    Handler、Looper和Message是Android系统提供的一套用于在不同线程之间传递消息和进行同步的关键组件。本文将深入探讨如何自定义Handler、Looper来实现线程间的通信。 首先,我们了解下Handler的基本原理。Handler是...

    Android应用源码之HandlerLooper2_Android.zip

    本压缩包"Android应用源码之HandlerLooper2_Android.zip"可能包含了关于这个主题的详细示例代码,让我们深入探讨这些关键组件的工作原理。 首先,`Handler`类是Android中处理消息和调度任务的核心组件。它允许...

    安卓Android源码——HandlerLooper2.rar

    这个压缩包“安卓Android源码——HandlerLooper2.rar”可能包含了关于这些组件的深入分析和示例代码。以下是关于`Handler`、`Looper`和`MessageQueue`的详细解释: 1. **Handler**: - `Handler`是Android中的一个...

    Android应用源码之HandlerLooper1_Android.zip

    这个压缩包“Android应用源码之HandlerLooper1_Android.zip”可能包含了一个示例项目,详细展示了如何在Android应用程序中使用这些组件。 首先,我们来深入理解`Handler`。`Handler`是Android中的一个关键类,主要...

    安卓Android源码——HandlerLooper1.rar

    这个`HandlerLooper1.rar`文件可能包含了对这些概念的深入解析和示例代码。 首先,我们来详细讲解`Handler`。`Handler`是Android中的一个类,它允许开发者在不同的线程中发送和处理消息。通常,我们在主线程(UI...

    Android应用源码之HandlerLooper1.zip

    本资料“Android应用源码之HandlerLooper1.zip”应该是包含了一个关于这些组件的详细示例或分析,让我们来深入探讨它们的工作原理。 首先,`Handler`是Android中的一个类,它用于在UI线程中发送和处理消息。当你...

    Android应用源码之HandlerLooper2.zip

    `Android应用源码之HandlerLooper2.zip`可能包含了一个示例项目,用于演示如何有效使用这些组件。以下是对这些核心概念的详细说明: 1. **Handler**: `Handler` 是一个用于在特定线程(通常是UI线程)中发送和...

    Android应用源码之HandlerLooper2.zip项目安卓应用源码下载

    Android应用源码之HandlerLooper2.zip项目安卓应用源码下载Android应用源码之HandlerLooper2.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考

    Android应用源码之HandlerLooper1.zip项目安卓应用源码下载

    Android应用源码之HandlerLooper1.zip项目安卓应用源码下载Android应用源码之HandlerLooper1.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考

    Handler Looper MessageQueue 源码解析

    在Android系统中,Handler、Looper和MessageQueue是实现线程间通信的核心组件,它们共同构建了一个消息处理机制。本文将深入解析这三者的源码,帮助你理解它们的工作原理,并教你如何手写一套自己的Handler系统。 ...

    模拟Android Handler机制Demo

    【Android Handler机制】是Android应用程序中用于线程间通信的核心组件,它与Looper和Message紧密配合,实现消息的发送、处理以及线程间的同步。在Android应用开发中,尤其是涉及到UI更新时,Handler机制显得尤为...

    应用源码之HandlerLooper1.zip

    在Android系统中,`...总之,"应用源码之HandlerLooper1.zip"是一个很好的学习资源,它提供了Android消息处理机制的实际示例,帮助开发者深入理解这一核心组件的内部工作原理,从而提升Android应用开发的专业技能。

    androidHandler测试的demo

    在“androidHandler测试的demo”中,我们可以预期包含以下内容: 1. 创建自定义`Handler`子类:这个子类可能重写了`handleMessage(Message msg)`方法,根据`msg.what`的值执行不同的操作,比如更新UI元素或执行特定...

    Handler和looper详解

    Handler和Looper是Android系统中两个非常重要的组件,它们之间相互关联,共同实现了Android系统中的消息处理机制。在本文中,我们将对Handler和Looper进行详细的解释,并探讨它们在Android系统中的作用。 一、...

    Android线程模式(handler,thread,looper)

    本文将深入探讨Android中的三种主要线程模式:Handler、Thread以及Looper,并结合源码分析它们的工作原理。 首先,我们来理解一下Android应用的基本运行环境。Android系统默认在主线程(UI线程)中执行所有的用户...

    Androdi msg handler looper学习源码

    深入理解Handler-Message-Looper机制对于优化Android应用的性能至关重要,因为它们是实现异步处理和避免UI阻塞的关键。在实际开发中,我们常利用这个机制来执行耗时操作(如网络请求)并在结果准备好后更新UI,确保...

    android Looper

    总之,`Looper`是Android系统中的核心组件之一,它与`Handler`和`Message`共同构建了强大的异步处理机制。理解和熟练运用`Looper`,对于开发高效、流畅的Android应用程序至关重要。通过阅读指定的博客文章,你可以更...

    Handler+Looper+MessageQueue

    【Android 线程间通信:Handler、Looper 和 MessageQueue 深度解析】 在 Android 应用开发中,为了保证界面的流畅性,我们通常需要将耗时操作放在非 UI 线程中执行,然后通过某种机制将结果传递回 UI 线程进行界面...

Global site tag (gtag.js) - Google Analytics