zoukankan      html  css  js  c++  java
  • 【Android】Handler、Looper源码分析

    一、前言

      源码分析使用的版本是 4.4.2_r1。

      Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制

      简单而言:Handler和Looper是对某一个线程实现消息机制的重要组成部分,另外两个重要元素是Message和MessageQueue,通过这四个类,可以让某个线程具备接收、处理消息的能力。

    二、源码剖析

      虽然只有四个类,而且这里只是剖析其中两个,但是也不能独立分析,必须组合进行解析。切入点是类Looper的注释中的一段示例代码:

     1 class LooperThread extends Thread {
     2      public Handler mHandler;
     3 
     4      public void run() {
     5           Looper.prepare();
     6 
     7           mHandler = new Handler() {
     8              public void handleMessage(Message msg) {
     9                  // process incoming messages here
    10               }
    11          };
    12          Looper.loop();
    13      }
    14 }

      这段代码描述了如何将一个普通的线程转变为一个Looper线程,即让它具备消息的循环处理能力。我们从Looper入手,看看这里到底做了什么。

    代码一:

     1 /** Initialize the current thread as a looper.
     2       * This gives you a chance to create handlers that then reference
     3       * this looper, before actually starting the loop. Be sure to call
     4       * {@link #loop()} after calling this method, and end it by calling
     5       * {@link #quit()}.
     6       */
     7     public static void prepare() {
     8         prepare(true);
     9     }
    10 
    11     private static void prepare(boolean quitAllowed) {
    12         if (sThreadLocal.get() != null) {
    13             throw new RuntimeException("Only one Looper may be created per thread");
    14         }
    15         sThreadLocal.set(new Looper(quitAllowed));
    16     }

      这里展示的是Looper的静态方法,即prepare(),前面代码中第5行调用。

      第13行可以看到一个运行时异常,其打印信息翻译为:每一个线程只允许拥有一个Looper,而且判断条件中用到ThreadLocal对象,如果不明白这是什么,可以参考我的另外一篇博客:深入理解ThreadLocal。总之,第一次调换用这个方法并且之前没有调用过,则会调用第15行的代码,这里实例化了一个Looper对象,其构造方法如下:

    代码二:

    1 private Looper(boolean quitAllowed) {
    2      mQueue = new MessageQueue(quitAllowed);
    3      mThread = Thread.currentThread();
    4 }

      第2行初始化了一个MessageQueue,顾名思义,就是为Looper创建绑定了一个消息队列。

      第3行则获取当前线程,即调用Looper的线程。这样即可将Looper绑定到一个线程上,同时为一个线程创建一个消息队列。

      在消息机制里面,Looper只是负责管理消息队列,也就是取出消息进行处理,而Handler则是负责发送消息以及处理消息的,那么Handler和Looper又是如何绑定到一起的呢?看切入点里面的7-11行,这里做了什么呢?下面的分析涉及到Looper中的几个方法,这里插入分析一下:

    代码三:

     1 /**
     2      * Return the Looper object associated with the current thread.  Returns
     3      * null if the calling thread is not associated with a Looper.
     4      */
     5     public static Looper myLooper() {
     6         return sThreadLocal.get();
     7     }
     8 
     9     /** Returns the application's main looper, which lives in the main thread of the application.
    10      */
    11     public static Looper getMainLooper() {
    12         synchronized (Looper.class) {
    13             return sMainLooper;
    14         }
    15     }

      很明显可以看到myLooper是获取属于当前线程的Looper,而getMainLooper则是获取应用的主Looper,它由属性sMainLooper引用,其赋值过程如下。

    代码四:

     1     /**
     2      * Initialize the current thread as a looper, marking it as an
     3      * application's main looper. The main looper for your application
     4      * is created by the Android environment, so you should never need
     5      * to call this function yourself.  See also: {@link #prepare()}
     6      */
     7     public static void prepareMainLooper() {
     8         prepare(false);
     9         synchronized (Looper.class) {
    10             if (sMainLooper != null) {
    11                 throw new IllegalStateException("The main Looper has already been prepared.");
    12             }
    13             sMainLooper = myLooper();
    14         }
    15     }

      注释中说到,这个方法不应该由程序员自己调用,我猜测这个方法应该是在应用启动的时候,由属于应用的第一个线程调用,之后如果再次调用,就会抛出异常了,因为sMainLooper实际上是一个static变量,也就是说它是属于整个应用的。

      准备完毕,现在回到主题,

    代码五:

     1     /**
     2      * Default constructor associates this handler with the {@link Looper} for the
     3      * current thread.
     4      *
     5      * If this thread does not have a looper, this handler won't be able to receive messages
     6      * so an exception is thrown.
     7      */
     8     public Handler() {
     9         this(null, false);
    10     }
    11     /**
    12      * Use the {@link Looper} for the current thread with the specified callback interface
    13      * and set whether the handler should be asynchronous.
    14      *
    15      * Handlers are synchronous by default unless this constructor is used to make
    16      * one that is strictly asynchronous.
    17      *
    18      * Asynchronous messages represent interrupts or events that do not require global ordering
    19      * with represent to synchronous messages.  Asynchronous messages are not subject to
    20      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
    21      *
    22      * @param callback The callback interface in which to handle messages, or null.
    23      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
    24      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
    25      *
    26      * @hide
    27      */
    28     public Handler(Callback callback, boolean async) {
    29         if (FIND_POTENTIAL_LEAKS) {
    30             final Class<? extends Handler> klass = getClass();
    31             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
    32                     (klass.getModifiers() & Modifier.STATIC) == 0) {
    33                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
    34                     klass.getCanonicalName());
    35             }
    36         }
    37 
    38         mLooper = Looper.myLooper();
    39         if (mLooper == null) {
    40             throw new RuntimeException(
    41                 "Can't create handler inside thread that has not called Looper.prepare()");
    42         }
    43         mQueue = mLooper.mQueue;
    44         mCallback = callback;
    45         mAsynchronous = async;
    46     }

      重点在于39-43行。第38行调用myLooper()方法获取属于本线程的Looper,如果你在这之前没有调用Looper.prepare()方法,则会返回null,此时就会抛出异常,要求你在这之前调用Looper.prepare()方法。而平时我们在主线程中使用Handler的时候,并不需要调用Looper.prepare()方法,这是因为主线程默认绑定一个Looper。

      接下去43行则是获取Looper的消息队列。

      除了这种简单的创建方式之外,Handler也还有别的创建方式,比如:

    代码六:

     1     /**
     2      * Use the provided {@link Looper} instead of the default one and take a callback
     3      * interface in which to handle messages.  Also set whether the handler
     4      * should be asynchronous.
     5      *
     6      * Handlers are synchronous by default unless this constructor is used to make
     7      * one that is strictly asynchronous.
     8      *
     9      * Asynchronous messages represent interrupts or events that do not require global ordering
    10      * with represent to synchronous messages.  Asynchronous messages are not subject to
    11      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
    12      *
    13      * @param looper The looper, must not be null.
    14      * @param callback The callback interface in which to handle messages, or null.
    15      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
    16      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
    17      *
    18      * @hide
    19      */
    20     public Handler(Looper looper, Callback callback, boolean async) {
    21         mLooper = looper;
    22         mQueue = looper.mQueue;
    23         mCallback = callback;
    24         mAsynchronous = async;
    25     }

      这里传入了一个Looper,而mLooper的赋值不是获取当前线程的Looper,而是直接取用该looper,这引起一个怀疑:一个Looper(或者说一个线程,因为是线程和Looper是一一对应的关系)可以绑定不止一个Handler,因为很明显我可以用一个Looper通过上述构造方法传入到不同的Handler中去,那么自然而然又想到一个问题:Handler是用于发送和处理消息的,那么当一个Looper绑定多个Handler的时候,发送来的消息肯定都是存储在Looper的消息队列中的,那么处理消息的时候,是怎么处理的呢?每一个Handler都处理一遍么?继续看源码,首先看发送消息的函数:

    代码七:

     1     public final boolean sendMessage(Message msg)
     2     {
     3         return sendMessageDelayed(msg, 0);
     4     }
     5 
     6     public final boolean sendEmptyMessage(int what)
     7     {
     8         return sendEmptyMessageDelayed(what, 0);
     9     }
    10 
    11     public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    12         Message msg = Message.obtain();
    13         msg.what = what;
    14         return sendMessageDelayed(msg, delayMillis);
    15     }
    16 
    17     public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    18         Message msg = Message.obtain();
    19         msg.what = what;
    20         return sendMessageAtTime(msg, uptimeMillis);
    21     }
    22 
    23     public final boolean sendMessageDelayed(Message msg, long delayMillis)
    24     {
    25         if (delayMillis < 0) {
    26             delayMillis = 0;
    27         }
    28         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    29     }
    30 
    31     /**
    32      * Enqueue a message into the message queue after all pending messages
    33      * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
    34      * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
    35      * You will receive it in {@link #handleMessage}, in the thread attached
    36      * to this handler.
    37      * 
    38      * @param uptimeMillis The absolute time at which the message should be
    39      *         delivered, using the
    40      *         {@link android.os.SystemClock#uptimeMillis} time-base.
    41      *         
    42      * @return Returns true if the message was successfully placed in to the 
    43      *         message queue.  Returns false on failure, usually because the
    44      *         looper processing the message queue is exiting.  Note that a
    45      *         result of true does not mean the message will be processed -- if
    46      *         the looper is quit before the delivery time of the message
    47      *         occurs then the message will be dropped.
    48      */
    49     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    50         MessageQueue queue = mQueue;
    51         if (queue == null) {
    52             RuntimeException e = new RuntimeException(
    53                     this + " sendMessageAtTime() called with no mQueue");
    54             Log.w("Looper", e.getMessage(), e);
    55             return false;
    56         }
    57         return enqueueMessage(queue, msg, uptimeMillis);
    58     }

      为了清晰,前面的方法全部都去掉了注释,只剩下最后一个方法,我们看到,往消息队列中添加消息,最后调用的是方法enqueueMessage。其实现如下:

    代码八:

    1     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    2         msg.target = this;
    3         if (mAsynchronous) {
    4             msg.setAsynchronous(true);
    5         }
    6         return queue.enqueueMessage(msg, uptimeMillis);
    7     }

      方法的最后调用了MessageQueue的enqueueMessage方法,从上面的流程可以看到,queue其实就是从mLooper中取出的MessgaeQueue。最终到了这里,消息可以通过Handler顺利压入绑定的Looper中的MessageQueue中去了。接下去就是消息的处理。这里需回到Looper中去,因为循环取出消息进行处理是Looper的工作。

      前面切入点代码中可以看到,在调用Looper.prepare()方法,实例化Handler之后,还有一个方法需要调用,即Looper.loop()方法。

    代码九:

     1  /**
     2      * Run the message queue in this thread. Be sure to call
     3      * {@link #quit()} to end the loop.
     4      */
     5     public static void loop() {
     6         final Looper me = myLooper();
     7         if (me == null) {
     8             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
     9         }
    10         final MessageQueue queue = me.mQueue;
    11 
    12         // Make sure the identity of this thread is that of the local process,
    13         // and keep track of what that identity token actually is.
    14         Binder.clearCallingIdentity();
    15         final long ident = Binder.clearCallingIdentity();
    16 
    17         for (;;) {
    18             Message msg = queue.next(); // might block
    19             if (msg == null) {
    20                 // No message indicates that the message queue is quitting.
    21                 return;
    22             }
    23 
    24             // This must be in a local variable, in case a UI event sets the logger
    25             Printer logging = me.mLogging;
    26             if (logging != null) {
    27                 logging.println(">>>>> Dispatching to " + msg.target + " " +
    28                         msg.callback + ": " + msg.what);
    29             }
    30 
    31             msg.target.dispatchMessage(msg);
    32 
    33             if (logging != null) {
    34                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    35             }
    36 
    37             // Make sure that during the course of dispatching the
    38             // identity of the thread wasn't corrupted.
    39             final long newIdent = Binder.clearCallingIdentity();
    40             if (ident != newIdent) {
    41                 Log.wtf(TAG, "Thread identity changed from 0x"
    42                         + Long.toHexString(ident) + " to 0x"
    43                         + Long.toHexString(newIdent) + " while dispatching to "
    44                         + msg.target.getClass().getName() + " "
    45                         + msg.callback + " what=" + msg.what);
    46             }
    47 
    48             msg.recycle();
    49         }
    50     }

      前面6-16行就不多解释了,关键看17行,这里是一个死循环,无限循环表示从队列中获取消息;第18行也很关键,这里调用MessageQueue的next方法获取下一个消息,很重要的地方在于注释:might block。可能会阻塞!如果不注意这一点,很可能就会误认为调用该方法,因为当时队列中还没有消息,所以就会执行第21行,直接返回了,而看到这个注释,再加上第20-22行的代码,我们容易猜测,MessageQueue通过在next()方法中返回null来表示整个队列的取消,从而终结消息机制,OK,不多说,言归正传,这一段代码最重要的是看31行:msg.target.dispatchMessage(msg);这行代码预示着如何处理消息!

      每一个Message都有一个target属性,该属性的声明如下:

    1    /*package*/ Handler target;  

      没错,是Handler类型!反观代码,在代码八的第2行,有一行很重要的代码被忽视了:

    1 msg.target = this;

      在Handler发送没一个消息进入队列之前,都会将其target设置为自己。从这里就可以看到之前那个问题(红色部分)的答案,消息是交给发送它的Handler处理的!接下来自然要去看的是Handler的dispatchMessage方法:

     1 /**
     2      * Handle system messages here.
     3      */
     4     public void dispatchMessage(Message msg) {
     5         if (msg.callback != null) {
     6             handleCallback(msg);
     7         } else {
     8             if (mCallback != null) {
     9                 if (mCallback.handleMessage(msg)) {
    10                     return;
    11                 }
    12             }
    13             handleMessage(msg);
    14         }
    15     }

      注释即说明它是处理消息的,在这里可以进行一些回调,这里不说明。主要看第13行,调用了handleMessage()方法,其实现如下:

    代码十一:

    1 /**
    2      * Subclasses must implement this to receive messages.
    3      */
    4     public void handleMessage(Message msg) {
    5     }

      终于到这一步了!注释中就能看到,我们在实例化Handler的子类的时候,是需要重载这个方法的,否则你的消息不会得到处理,实现参见切入点8-11行!具体使用可以参见我的博客Android Handler机制

     

    三、总结

      源码剖析中,主要关注的对象是:Thread,Handler,Looper三个重量级对象是如何绑定到一起的,以及消息是如何在Handler和Looper中存在和传播的,从源码中看这个过程非常清楚。其实整个设计并没有什么新奇的技巧,但是设计非常合理,值得借鉴。

      下一篇博客会去探索一下MessageQueue,关于MessageQueue如何管理消息,和Looper一起实现延迟消息,我非常感兴趣。

  • 相关阅读:
    二分图最大匹配(匈牙利算法) POJ 3041 Asteroids
    贪心 FZU 2013 A short problem
    数学 FZU 2074 Number of methods
    莫队算法/二分查找 FZU 2072 Count
    畅通工程 HDU
    Minimum Inversion Number~hdu 1394
    I Hate It HDU
    A Simple Problem with Integers~POJ
    敌兵布阵
    Coins HDU
  • 原文地址:https://www.cnblogs.com/lqminn/p/3751820.html
Copyright © 2011-2022 走看看