handler机制详解

Handler详解

  • 在ui线程中我们之后new Handelr()然后实现子线程和主线程的通讯是没有问题的。那是因为在ActivityThread类中调用了Loop.Preapre();和Looper.loop()方法 现在我们在子线程模拟这个过程
  • 在子线程中
  • 代码如下
    new Thread(){
    public void run() {

            Handler handler=new Handler();
        };
    }.start();
    

    • 发现异常 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    • 我们只是写了new Handler()就报了一个异常,因此我们查看下构造方法
      mLooper = Looper.myLooper();
      if (mLooper == null) {
      throw new RuntimeException(
      "Can't create handler inside thread that has not called Looper.prepare()");
      }
    • 构造方法中先调用Looper.myLooper() ,之后判断是否为null,如果为null 抛出异常 因此我们可以肯定,这里的mLooper肯定为null
    • 因此我们得查看Looper.myLooper()方法是怎么工作的
    • Looper.myLooper(); 源码public static Looper myLooper() {
      return sThreadLocal.get();
      }
    • 这里引入了一个sThreadLocal.get();本地线程的get方法,我们继续查看get()返回的是什么?
    • 首先我们产看ThreadLocal类的功能

    Implements a thread-local storage, that is, a variable for which each thread
    has its own value. All threads share the same {@code ThreadLocal} object

发现ThreadLocal就是给线程储存了一个共享的对象
  • 接下来我们看一看Looper.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));
    }

  • 可以看到sThreadLocal将我们的Looper对象存放到了线程中
  • 这也就能解释当我们new Hander()的时候,抛出异常,是因为直接Looper.myLooper();拿到的为空,如果我们prepare()的话 ,就给sThreadLocal存放了一个looper,因此也就不为null了,通过源代码,也可以发现一个线程只能有一个looper和Message,但是可以有多个handelr
  • 那么looper.loop()方法的作用是什么呢?是让消息泵循环起来,去Messagequeue中读取消息,不loop起来的话 sendMessage()无效
  • ` public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
    throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);
    }
    final MessageQueue queue = me.mQueue;

    // 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.recycle();
    }
    

    }`

  • 大家看源代码可以看到 Looper.loop()首先拿到自己的Looper,之后拿到消息队列,也就是MessageQueue,因此可以看到MessageQueue在Looper中,因此一个线程只能有一个Looper,也只能有一个MessageQueue
  • 之后是一个死循环,不断的调用msg.next();可能被阻塞,类似Socket的服务器端,之后分发出去
  • 接着我们看sendMessage方法

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

    `

  • 最终将消息存放到了消息队列中 ,looper的话就直接从MessageQueue死循环读取

总结

  • handler.sendMessage()的功能是将Message()放到Hander中的MessageQueue中
  • Looper.prepare()是将Looper绑定到本线程ThreadLocal中
  • new Handelr()的时候 获得了ThreadLocal中绑定的Looper
  • Looper.loop()的时候,是死循环遍历MessageQueue,拿到消息给了msg.target,这个target指的就是发送消息的那个handelr
  • 一个thread中只能有一个Looper和MessageQueue,但是可以多个handler,因为在handler.sendMessage()的时候,Message被放到messagequeue的时候,已经和发送的hanlder绑定了,之后再loop的时候是msg.target.dispatch分发出去
  • handler和Looper共用的是MessageQueue
  • Messagequeue是Looper的一个成员变量
  • ThreadLocal 是保存线程共享的内容的,这里用来保存了Looper

你可能感兴趣的:(handler,流程分析)