Handler

Handler的消息循环涉及的类:Handler,Looper,Message,MessageQueue

创建


  1. ActivityThread main方法中创建 Looper

     public static void main(String[] args) {
     		Looper.prepareMainLooper();
     		...
     		Looper.loop();
     }
    
  2. Looper prepare 方法中,通过 ThreadLocal 将 Looper 和 主线程进行绑定

     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));
     }
    
  3. Looper 的私有化构造方法中 绑定了 MessageQueue

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

发送一个Message的流程


  1. 初始化Handler,获取并绑定当前线程的 MessageQueue 和 Looper,可以看到这个方法中有一个异常,如果是异步线程的话需要先调用 Looper.prepare()。

     public Handler(Callback callback, boolean async) {
     		...
         mLooper = Looper.myLooper();
         if (mLooper == null) {
             throw new RuntimeException(
                 "Can't create handler inside thread " + Thread.currentThread()
                         + " that has not called Looper.prepare()");
         }
         mQueue = mLooper.mQueue;
         mCallback = callback;
         ...
     }
    
  2. 发送消息最终都会调用到 Handler.enqueueMessage(MessageQueue, Message, updateTime) 方法

     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
         // 这里将当前的 Message 和 Handler 绑定
     		msg.target = this;
         if (mAsynchronous) {
             msg.setAsynchronous(true);
         }
         return queue.enqueueMessage(msg, uptimeMillis);
     }
    
  3. 将当前Message 放入 MessageQueue,如果队列中没有消息,直接将这个消息放在队首,如果队列中有消息,根据这个消息的接收处理时间,将其插入到合适的位置。

     boolean enqueueMessage(Message msg, long when) {
     		...
         synchronized (this) {
             if (mQuitting) {
                 IllegalStateException e = new IllegalStateException(
                         msg.target + " sending message to a Handler on a dead thread");
                 Log.w(TAG, e.getMessage(), e);
                 msg.recycle();
                 return false;
             }
     
             msg.markInUse();
             msg.when = when;
             Message p = mMessages;
             boolean needWake;
             if (p == null || when == 0 || when < p.when) {
                 // New head, wake up the event queue if blocked.
                 msg.next = p;
                 mMessages = msg;
                 needWake = mBlocked;
             } else {
                 // Inserted within the middle of the queue.  Usually we don't have to wake
                 // up the event queue unless there is a barrier at the head of the queue
                 // and the message is the earliest asynchronous message in the queue.
                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
                 Message prev;
                 for (;;) {
                     prev = p;
                     p = p.next;
                     if (p == null || when < p.when) {
                         break;
                     }
                     if (needWake && p.isAsynchronous()) {
                         needWake = false;
                     }
                 }
                 msg.next = p; // invariant: p == prev.next
                 prev.next = msg;
             }
     
             // We can assume mPtr != 0 because mQuitting is false.
             if (needWake) {
                 nativeWake(mPtr);
             }
         }
         return true;
     }
    

消费消息


  1. 主线程初始化的时候有这样一段代码,将主线程绑定一个Looper,然后调用了 Looper.loop 方法轮询消息队列

     public static void main(String[] args) {
     		Looper.prepareMainLooper();
     		...
     		Looper.loop();
     }
    
  2. Looper.loop() 初始化主线程时,开启了消息循环,通过 MessageQueue 的 next 方法获取下一个消息,最终调用了 msg.target.dispatchMessage(msg); 将消息分发出去处理。处理玩这个消息后,调用 msg.recycleUnchecked() 这个方法,将它重新放回 消息池 中

     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;
         ...
         for (;;) {
             Message msg = queue.next(); // might block
             if (msg == null) {
                 // No message indicates that the message queue is quitting.
                 return;
             }
     				...
             try {
                 msg.target.dispatchMessage(msg);
                 dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
             } finally {
                 if (traceTag != 0) {
                     Trace.traceEnd(traceTag);
                 }
             }
     				...
     				msg.recycleUnchecked();
         }
     }
    
  3. MessageQueue 中轮询下一个消息的方法,这里Message 有一个回收池,只会获取到最新的 Message,将当前的 Message 取出,并且 next 设置为null,同事将 mMessages 指向其下一个 Message。

     Message next() {
         ...
         for (;;) {
             if (nextPollTimeoutMillis != 0) {
                 Binder.flushPendingCommands();
             }
     
             nativePollOnce(ptr, nextPollTimeoutMillis);
     
             synchronized (this) {
                 // Try to retrieve the next message.  Return if found.
                 final long now = SystemClock.uptimeMillis();
                 Message prevMsg = null;
                 Message msg = mMessages;
                 if (msg != null && msg.target == null) {
                     // Stalled by a barrier.  Find the next asynchronous message in the queue.
                     do {
                         prevMsg = msg;
                         msg = msg.next;
                     } while (msg != null && !msg.isAsynchronous());
                 }
                 if (msg != null) {
                  ...
                           if (prevMsg != null) {
                               prevMsg.next = msg.next;
                           } else {
                               mMessages = msg.next;
                           }
                           msg.next = null;
                           if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                           msg.markInUse();
                           return msg;
                   ...
                   } else {
                       // No more messages.
                       nextPollTimeoutMillis = -1;
                   }
     
                   // Process the quit message now that all pending messages have been handled.
                   if (mQuitting) {
                       dispose();
                       return null;
                   }
     							...
           }
       }
    
  4. 调用 msg.target.dispatchMessage(msg); 去分发处理这个消息,其中 target 就是 Handler,最终调用的是 Handler 的 dispatchMessage 的方法

     public void dispatchMessage(Message msg) {
         if (msg.callback != null) {
             handleCallback(msg);
         } else {
             if (mCallback != null) {
     						// handleMessage 这两个方法都需要 Handler 去实现,
     						//都是重写方法,理论上不会同时存在
                 if (mCallback.handleMessage(msg)) {
                     return;
                 }
             }
             handleMessage(msg);
         }
     }
     
     private static void handleCallback(Message message) {
     		// callback 就是 Runnable 这个就能实现子线程 Runnable 中的代码 最终在主线程中执行
         message.callback.run();
     }
    

为什么不能在子线程创建 Handler

  1. 可以看到 Handler 初始化的时候 有这样一句代码:Looper.myLooper();

     public Handler(Callback callback, boolean async) {
     		...
         mLooper = Looper.myLooper();
         if (mLooper == null) {
             throw new RuntimeException(
                 "Can't create handler inside thread " + Thread.currentThread()
                         + " that has not called Looper.prepare()");
         }
         mQueue = mLooper.mQueue;
         mCallback = callback;
         ...
     }
    
     public static @Nullable Looper myLooper() {
         return sThreadLocal.get();
     }
    

    并且在 消息系统初始化的时候有这样一段代码

     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 是 ThreadLocal 的一个实例,他实际上是一个 Map,Thread 作为它的 Key,Looper 作为他的 value。

    其中 Thread 是通过 Thread.currentThread() 获取的,直接在子线程中创建Handler,调用了 sThreadLocal.get() 的方法,此时返回的一定为 null,会抛出异常。所以需要先调用 Looper.prepare() 方法,给当前线程创建一个 Looper。

    其中 Thread 中维护了一个 ThreadLocalMap,每次创建的 ThreadLocalMap,最终是被 Thread 持有的,真正的 Key value 存ThreadLocalMap里,而且这个 的 key 是通过一个弱引用持有的,所以当前线程执行完毕后,回收就回收了,不会继续持有当前的 Thread,不会造成内存泄漏。ThreadLocal只是 Thread 和 ThreadLocalMap 的操作类。

View.post 和 Handler.post 的区别

textView.setText 只能在主线程执行么

ThreadLocal 的用法和原理