唠叨一下:
Android大部分底层机制并不难,但在学习过程中如果运用线性思维且抓不住重点就容易陷入到海量的源码中。具有化繁为简、理解原理并非死记硬背的能力才能在繁杂的Android体系中逐步建立自己的知识框架。
Handler定义:
Handler官方定义的两个主要功能: (1)定时执行Message和runnable (2)将任务插入另一个线程的队列中
Handler流程:
构造Handler需要一个Looper,每个线程只能有一个Looper,Looper中包含一个MessageQueue。Handler发送消息时调用了MessageQueue的enqueueMessage方法将消息入列。Looper通过loop方法取出消息,并在Handler的handleMessage方法中处理。
Handler构造函数:
Handler的构造方法最后都会调用两个方法 Handler(Callback callback, boolean async) 和Handler(Looper looper, Callback callback, boolean async)。第一个方法会去获取当前线程的Looper,未找到则报错。
Looper:
非主线程默认没有消息队列,需要调用Looper.prepare方法去创建。下图可以看到通过sThreadLocal.set() 和 get()可以创建和获取当前线程的Looper。
public static void prepare() {
prepare(true);
}
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));
}
ThreadLocal:
ThreadLocal提供线程本地变量,这些变量是线程隔离的。下图可见Thread和Looper是通过键对值的方式储存在ThreadLocalMap中的。ThreadLocalMap的源码比较难搞,继续了解的话推荐一篇博客ThreadLocal源码解读 - 活在夢裡 - 博客园
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, 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;
}
}
return setInitialValue();
}
消息入列:
Handler调用post、postDelay等方法最后均会走到MessageQueue的enqueMessage方法。下图if()中当消息队列为空或该消息不是延迟消息或时间早于头消息则将该消息做为头消息。其情况进入else()则遍历整个队列,找到合适的位置插入。
boolean enqueueMessage(Message msg, long when) {
...
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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;
...
}
}
return true;
}
消息取出:
Looper通过loop方法取出消息,关键代码如下。这里的target指要发送的Handler
public static void loop() {
...
for (;;) {
Message msg = queue.next();
...
try {
msg.target.dispatchMessage(msg);
}
}
}
上图next方法调用的是MessageQueue的next()。关键代码如下
Message next() {
if (msg != null) {
if (now < msg.when) {
// 时间未到,设置timeout继续休眠
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 消息出列
mBlocked = false;
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 {
// 队列没有消息,永久休眠
nextPollTimeoutMillis = -1;
}
}