Handler,Looper,MessageQueue原理分析

作者: HarryXR | 来源:发表于2016-08-11 13:33 被阅读218次

    Handler机制在android开发中经常使用,一直没搞明白Handler,Looper,MessageQueue它们之间的关系,此次就从源码的角度分析一下

    1. 简述

    Looper负责创建MessageQueue,然后进入无限循环体中不断从MessageQueue取出消息,触发消息的分发处理,而Handler负责发送消息

    2.源码分析

    • Looper
      主要就是prepare和loop方法

    prepare()方法:

    private static void prepare(boolean quitAllowed) { 
      if (sThreadLocal.get() != null) {       
        throw new RuntimeException("Only one Looper may be created per thread");   
     }    
      sThreadLocal.set(new Looper(quitAllowed));
    }
    

    从上面看出ThreadLocal存储了Looper对象,而且此方法不能运行两次,否则抛出异常.

    loop()方法:
    >public static void loop() {
    final Looper me = myLooper(); //获得Looper
    if (me == null) {
    throw new RuntimeException("No Looper; Looper.prepare() wasn't
    called on this thread.");
    }
    final MessageQueue queue = me.mQueue; //获得MessageQueue
    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    for (;;) { //此处无限循环,取出消息
    Message msg = queue.next();
    // might block
    if (msg == null) {
    // No message indicates that the message queue is quitting.
    return;
    }
    // This must be in a local variable, in case a UI event sets the logger
    Printer logging = me.mLogging;
    if (logging != null) {
    logging.println(">>>>> Dispatching to " + msg.target + " " +
    msg.callback + ": " + msg.what);
    }
    msg.target.dispatchMessage(msg); //分发处理消息
    if (logging != null) {
    logging.println("<<<<< Finished to " + msg.target + " " +
    msg.callback);
    }
    // Make sure that during the course of dispatching the
    // identity of the thread wasn't corrupted.
    final long newIdent = Binder.clearCallingIdentity();
    if (ident != newIdent) {
    Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " " + msg.callback + "
    what=" + msg.what);
    }
    msg.recycleUnchecked();
    }}

    首先myLooper()从ThreadLocal中获取Looper对象,如果looper为null则抛出异常,也说明prepare()在loop()之前运行
    >public static Looper myLooper() {
    return sThreadLocal.get();
    }

    下一步是拿到MessageQueue,即me.Queue;
    再进入开头所说的无限循环,取出消息msg;
    最后就是msg.target.dispatchMessage(msg),分发处理,target就是Handler.

    概括Looper作用:

    1. 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
    2. loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
      下面就该Handler发送消息了
    • Handler
    1. Handler与MessageQueue绑定
      看Handler构造方法

      public Handler() {  
          this(null, false);  
       }  
       public Handler(Callback callback, boolean async) {  
       if (FIND_POTENTIAL_LEAKS) {  
           final Class<? extends Handler> klass = getClass();  
           if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
                   (klass.getModifiers() & Modifier.STATIC) == 0) {  
               Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
                   klass.getCanonicalName());  
           }  
       }  
       mLooper = Looper.myLooper();  
       if (mLooper == null) {  
           throw new RuntimeException(  
               "Can't create handler inside thread that has not called Looper.prepare()");  
       }  
       mQueue = mLooper.mQueue;  
       mCallback = callback;  
       mAsynchronous = async;  
      }  
      

    通过Looper.myLooper()获取了当前线程保存的Looper实例,然后又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了

    下面看发送消息的方法

    public final boolean sendMessage(Message msg)  
      {  
            return sendMessageDelayed(msg, 0);  
      } `
    

    public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {   
           delayMillis = 0;   
        }    
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}
    

    最后到:

        public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 
          MessageQueue queue = mQueue;  
           if (queue == null) {  
             RuntimeException e = new RuntimeException(  
                   this + " sendMessageAtTime() called with no mQueue");  
             Log.w("Looper", e.getMessage(), e);  
             return false;  
         }  
           return enqueueMessage(queue, msg, uptimeMillis);  
    }       
    

    此处调用了下面这个方法:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
       msg.target = this;  
       if (mAsynchronous) {  
           msg.setAsynchronous(true);  
       }  
       return queue.enqueueMessage(msg, uptimeMillis);  
      }                                                                                                                   
    

    nqueueMessage中首先为msg.target赋值为this,也就是把当前的handler作为msg的target属性。最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。

    现在已经很清楚了Looper会调用prepare()和loop()方法,在当前执行的线程中保存一个Looper实例,这个实例会保存一个MessageQueue对象,然后当前线程进入一个无限循环中去,不断从MessageQueue中读取Handler发来的消息。然后再回调创建这个消息的handler中的dispathMessage方法,下面我们赶快去看一看这个方法:

    public void dispatchMessage(Message msg) {  
        if (msg.callback != null) {  
            handleCallback(msg);  
        } else {  
            if (mCallback != null) {  
                if (mCallback.handleMessage(msg)) {  
                    return;  
                }  
            }  
            handleMessage(msg);  
        }  
    }  
    

    可以看到调用了 handleMessage(msg)方法;

     public void handleMessage(Message msg) {  
    }  
    

    这是一个空方法,因为消息的最终回调都是我们自己实现的,在handler中实现handleMessage();

    好了,现在总结一下整个流程:
    1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
    2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
    3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
    4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
    5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

    • Handler post
      一般使用方法
      mHandler.post(new Runnable()
      {
      @Override
      public void run()
      {
      Log.e("TAG", Thread.currentThread().getName());
      }
      });
      看输出结果,当前thread就是handler所在线程,并不会单独创建线程,看源码:

       public final boolean post(Runnable r)  
       {  
        return  sendMessageDelayed(getPostMessage(r), 0);  
       }  
      

       private static Message getPostMessage(Runnable r) {  
        Message m = Message.obtain();  
        m.callback = r;  
        return m;  
        }  
    

    可以看到就是将runnable设置为msg.callback,下面和handler.sendMessage一样,最终到dispatchMessage:

    public void dispatchMessage(Message msg) {  
       if (msg.callback != null) {  
           handleCallback(msg);  
       } else {  
           if (mCallback != null) {  
               if (mCallback.handleMessage(msg)) {  
                   return;  
               }  
           }  
           handleMessage(msg);  
       }  
     }  
    

    此时因msg.callback != null,所以直接执行handleCallback(msg);

    private static void handleCallback(Message message) {        
        message.callback.run();
      }  
    

    handleCallback()其实就只执行的Runnable的run方法,所以handler.post不会另开线程;
    嗯,到此就全部结束了,相信对Handler,Looper,MessageQueue之间的关系都有了解了吧.

    相关文章

      网友评论

        本文标题:Handler,Looper,MessageQueue原理分析

        本文链接:https://www.haomeiwen.com/subject/ekajsttx.html