MessageQueue原理
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<? 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());
}
}
// 从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 ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal.set(new Looper(quitAllowed));
}
// 可以看到获取当前线程的Looper是通过sThreadLocal.get()拿到的
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
1.1 刚分析了prepare的源码就发现一个非常重要的ThreadLocal
sThreadLocal: static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
我们跟进去搞清楚
// 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);
}
}
@SuppressLint("HandlerLeak")
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// priority2
Log.e("TAG", "This is Handler.mCallback");
return false;
}
}) {
@Override
public void handleMessage(Message msg) {
// priority3
Log.e("TAG", "This is Handler.handleMessage");
}
};
Message msg = Message.obtain(handler, new Runnable() {
@Override
public void run() {
// priority1
Log.e("TAG", "This is Message.callback");
}
});
msg.sendToTarget();
分析到这里整个安卓的消息机制就明了了, 接下来总结一波
总结
- 创建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()中
网友评论