Handler机制主要分为两部分:发送消息和处理消息;
发送消息:可以在任意的子线程中进行操作;
处理消息:在主线程中进行操作,主要是通过Looper类轮询MessageQueue队列来处理消息的;
handler中的发送消息的方法有很多种;但是这些方法经过处理最终会调用到Handler.enqueueMessage();
发送消息:
1.调用sendMessage方法,将消息传递到MessageQueue队列中
2.使用handler.post(new Runnable(){.....}) //作为message.callback的值,传递给MessageQueue队列
处理消息:
在主线程ActivityThread类中,调用Looper.loop()方法,在该方法中轮询消息队列MessageQueue,然后执行这些消息;
Handler机制在源码层可以分为4层:
Looper机制:sThreadLocal,Looper.loop();
Message:消息的数据结构,消息缓存池;
MessageQueue:enqueueMessage,next,消息等待,同步消息隔离,idleHandler;
Handler:send/post,dispatchMessage消息处理优先级;
1.Looper机制:
sThreadLocal:静态常量,保证一个线程只有一个 Looper;
sMainLooper:静态变量,在 prepareMainLooper 中赋值当前线程 Looper;
mQueue:变量,Looper 构造函数中初始化,因为一个线程只有一个 Looper,所以也同样只有一个 mQueue。
通过以上分析,我们可以总结出一下特性:
Looper、MessageQueue 是线程唯一的;
一个进程只有一个 sMainLooper;
根据 ThreadLocal 的特性,可通过 myLooper 方法获取当前线程的 Looper。
Looper.loop():
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
...
msg.target.dispatchMessage(msg);
...
msg.recycleUnchecked();
}
}
Looper.loop() 方法虽然看起来很多,其实他主要就做了三件事:
从消息队列中获取下一个消息;
msg.target 就是 handler,通过 dispatchMessage 方法把消息分发下去,这个方法下面会有说到;
消息回收,放到消息缓存池里。这里需要注意的是 Message 对象并没有释放,会缓存起来。
2.Message数据结构:
public int what, arg1, arg2;
public Object obj;
public Messenger replyTo;
int flags;
long when; // 消息发送时间
Bundle data;
Handler target;
Runnable callback;
Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
看到 next 变量,我们会想到单链表,其实 Message 就相当于单链表的 node,MessageQueue 就是一个单链表了,会持有表头的引用;
what、arg1、arg2、obj、data 就是我们发送的一些信息;
值得注意的是 target,他是 Handler 类型,就是本消息的 Handler,会在 Handler 发送消息的时候赋值;
后面的四个对象,都是和消息缓存池有关的。
3.MessageQueue消息队列:
主要作为插入队列的方法,有下列几个特性:
把消息加入消息队列,如果当前表头为空,则把消息作为表头引用;如果不为空,则会根据时间的顺序,插入到对应的时间中;
nativeWake 是调用底层在管道中写操作以唤醒,在队列不是阻塞的状态下是不需要唤醒的;
另外注意其中用了 synchronized 关键字,说明消息队列的插入是线性安全的,删除也是线性安全的,之后我们会说到。