一. 常用的几种方式
// 方式1Handler handler = new Handler();Message message = Message.obtain();handler.sendMessage(message);// 方式2Handler handler = new Handler(Looper.getMainLooper());handler.post(new Runnable(){...});复制代码
二. MessageQueue原理
/** * Handler.sendMessage -> Handler.sendMessageDelayed */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } // sendMessage最终会调用sendMessageAtTime这个方法 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); } // 将我们创建的这个Message投放到消息队列中去 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }复制代码
好了上面我们看到, 我们创建的Message最后会被投放到消息队列中去, 这个消息队列做了哪些处理呢, 我们跟进入MessageQueue中去看看
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } // 若这个Message已经标记为正在被使用, 则抛出异常 if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } 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标记为正在使用的状态 msg.when = when;// 该msg发送的时间 Message p = mMessages;// mMessages为MessageQueue的首元素 boolean needWake; // 1. 这个if判断是为了确定在未来一段时间里会最先发送的msg, 将其插入到Message链表的首部 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p;// 插入到链表首部 mMessages = msg;// 让mMessage指向链表的首元素 needWake = mBlocked; } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; // 2. 这个for循环从链表的首部开始, 找寻一个适合msg插入的位置, 将其插入到prev的后面和p的前面 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; }复制代码
我们看到从if (p == null || when == 0 || when < p.when)开始往下的代码就开始了Message的链表操作了 这里我们指定:
- Message msg1 = Message.obtain(); handler.sendMessage(message);
- Message msg2 = Message.obtain(); handler.sendMessageDelay(message, 1000);
- Message msg3 = Message.obtain(); handler.sendMessageDelay(message, 500);
- 当我们的消息msg1进入MessageQueue时
- msg1.when = when; (msg1.when = 0)
- Message p = mMessages (p = null)
- ==if (p == null || when == 0 || when < p.when) 显然满足==
- msg1.next = p; (msg1.next = null)
- mMessages = msg1
- 当我们的消息msg2进入MessageQueue时
- msg2.when = when; (msg2.when = 1000)
- Message p = mMessages; (Message p = msg1)
- ==if (p == null || when(1000) == 0 || when(msg2.when -> 1000) < p.when(msg1.when -> 0)) 不满足条件==
- Message prev = p; (Message prev = mMessages -> Message prev = msg1)
- p = p.next; (p = mMessages.next -> p = msg1.next -> p = null )
- ==if (p == null || when(msg2.when -> 1000) < p.when(null) ) 显然满足条件, break, 退出死循环==
- msg2.next = p; (msg2.next = null)
- prev.next = msg2;(mMessages.next = msg2 -> msg1.next = msg2)// 这样就建立了msg1与msg2的链表关系
- 当我们的消息msg3进入MessageQueue时
- msg3.when = when; (msg3.when = 500)
- Message p = mMessages; (Message p = msg1)
- ==if (p(msg1) == null || when(500) == 0 || when(msg3.when -> 500) < p.when(msg1.when -> 0)) 不满足条件==
- Message prev = p; (Message prev = mMessages -> Message prev = msg1)
- p = p.next; (p = mMessages.next -> p = msg1.next -> p = msg2 )
- ==if (p(msg2) == null || when(msg3.when -> 500) < p.when(msg2.when -> 1000) ) 显然满足条件, break, 退出死循环==
- msg3.next = p; (msg3.next = msg2)
- prev.next = msg3;(msg1.next = msg3) 真是令人惊叹, 我们发送的Message经过这套算法之后, 按照时间发送早晚的顺序链接排序好了
可以看到主要的算法就是使用了一个重要的if判断和一个for循环:
- if (p == null || when == 0 || when < p.when)
- 这个if判断是为了确定在未来一段时间里会最先发送的msg
- 将其插入到Message链表的首部
- 让mMessages指向链表的首部
- for (;;)这个for循环从链表的首部开始, 找寻一个适合当前传入的msg插入的位置, 将其插入到prev的后面和p的前面
Summary:
sendMessage方法只是将我们创建的Message投放到消息队列MessageQueue, 这个队列是以链表的方式按照msg发送时间的顺序排列
三. Looper消息循环机制
在线程中无法直接创建Handler
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class 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()); } } // 从Handler的构造方法可知, Handler是无法再直接在子线程中创建的 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } // 这里有个Queue, Nice, This is MessageQueue mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }复制代码
正确创建Handler的姿势如下
// 在子线程中创建 Thread({ // 1. 准备Looper循环 Looper.prepare() Handler() Log.e("TAG", Thread.currentThread().toString()) // 2. 开启循环 Looper.loop() }).start() // Android的主线程中ActivityThread.class public static void main(String[] args) { ... // 可以看到这里也执行了Looper的prepare方法 // 我们能在主线程中直接创建Handler肯定也不是凭空来的 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); }复制代码
- 分析Looper的prepare方法
public static void prepare() { prepare(true); } public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } // 将我们的Looper set进ThreadLocalMap中 // static final ThreadLocalsThreadLocal = new ThreadLocal (); sThreadLocal.set(new Looper(quitAllowed)); } // 可以看到获取当前线程的Looper是通过sThreadLocal.get()拿到的 public static @Nullable Looper myLooper() { return sThreadLocal.get(); } 复制代码
1.1 刚分析了prepare的源码就发现一个非常重要的ThreadLocal sThreadLocal: static final ThreadLocal sThreadLocal = new ThreadLocal(); 我们跟进去搞清楚
// ThreadLocal.class 的set方法 public void set(T value) { // 一个线程中有一个唯一的ThreadLocalMap用于存储键值对 Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);// ThreadLocalMap map = t.threadLocals; if (map != null) // key: ThreadLocal, value: T map.set(this, value); else // 给线程创建 ThreadLocalMap 并且将当前的 TheadLocal 和 value 加入其中 // 一般情况下在线程初始化时会被自动创建 createMap(t, value);// t.threadLocals = new ThreadLocalMap(this(当前ThreadLocal的实例), value); } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } // 通过跟进源码可知initialValue就是null return setInitialValue(); }复制代码
可以看到, 我们的sTheadLocal.set(value)方法, 将sThreadLocal和value值set进了ThreadLocalMap中, 这个ThreadLocalMap在一个线程中是唯一的, 而sThreadLocal的value又对应了我们new 的Looper对象, 这样我们就可以通过sTheadLocal.get()方法去获取到我们存入的value了, 这里主要分析Looper相关机制, 对于ThreadLocal存储的细节这里不做深究
- 接下来看看Looper.loop做了哪些操作
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); // 在new Looper()的时候, 会创建一个MessageQueue对象 // 这里获取到这个MessageQueue对象 final MessageQueue queue = me.mQueue; for (;;) {// 可以看到这里是个死循环 // 从MessageQueue队列中取出下一个需要执行Message Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } msg.recycleUnchecked(); } }复制代码
上述代码中有两行非常值得关注
- Message msg = queue.next();// 从消息队列中取出当前时间节点需要执行的msg
- msg.target.dispatchMessage(msg);// 分发这个取出的msg
2.2 看看MessageQueue.next()方法是如何取出msg的
// 从MessageQueue中取出一下个需要执行的Message Message next() { ... // 可以看到MessageQueue的next方法也是一个死循环 for (;;) { ... synchronized (this) { // 尝试从Queue中取出下一个需要执行的Message final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; // 判断当前Queue首部的Msg是否绑定了Target(Handler), 即判断mMessge是否可用 if (msg != null && msg.target == null) { // 循环找出当前队里第一个可用的msg do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { // 判断当前时间节点是否大于Msg需要执行的时间 if (now > msg.when) { if (prevMsg != null) { // msg即将被取出, 所以它之前的prevMsg的next直接链接上msg的next prevMsg.next = msg.next; } else { // msg即将被取出, 队首元素指向下一个 mMessages = msg.next; } // 将这个msg指向的下一个位置置空 msg.next = null; // 标记为使用状态 msg.markInUse(); // 将msg取出, 返回出去 return msg; } } else { // No more messages. } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } } } }复制代码
从上面的代码中可以看到Looper.loop中维护了一个for(;;)死循环, MessageQueue.next中也维护了一个for(;;)死循环
- 第一个死循环的作用是: 循环的从MessageQueue中取出msg, 通过dispatchMessage分发并处理
- 第二个死循环的作用是: 循环的从MessageQueue中尝试去取出当前可以执行的msg, 将其返回给Loop的loop方法处理并分发
2.3 Handler的dispatchMessage分发处理Msg
/** * Handle system messages here. * 终于我们最终还是走到了这个方法中去处理Msg */ public void dispatchMessage(Message msg) { // priority1: 处理msg携带的callback if (msg.callback != null) { handleCallback(msg); } else { // priority2: 处理给Handler设置的mCallback对象中的handleMessage方法 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } // priority3: 处理Handler重写的handleMessage(msg)方法 handleMessage(msg); } }复制代码
分析到这里整个安卓的消息机制就明了了, 接下来总结一波
总结
- 创建Handler首先要初始化当前线程的Looper, 即Looper.prepare()
- 在Looper创建的时, 会创建当前线程的MessageQueue消息队列即Looper.mQueue
- 当我们通过Handler在其它线程中发送Message时, 会将其投递到Handler创建线程所在的MessageQueue中
- 在Handler创建线程的Looper.loop()方法中, 会不断的循环通过MessageQueue.next()取出当前时间节点需要执行的Message
- 取出Message后通过 msg.target.dispatchMessage(msg) 方法分发处理这个Msg, 至此就走到了handleMessage()中