本文主要讲Handler+MessageQueue+Looper+ThreadLocal+Thread之间的逻辑关系,以及对源码的分析
1:我们在每次创建Handler对象时,需要绑定Looper,而Looper对象在每个线程中只会存在一个,MessageQueue则是Looper对象中的全局变量。以下是逻辑图。
2:为什么我们在主线程创建Handler对象却没有绑定Looper。以下是源码:
public Handler() { this(null, false); }
public Handler(Callback callback, boolean async) {
//省略
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
所以从以上代码看出,主线程创建的空构造函数handler,实际上内部取绑定主线程handler(mLooper = Looper.myLooper())。
2:为什么主线程调用 Looper.myLooper() 是绑定对应主线程的 Looper。以下是源码:
public static Looper myLooper() { return sThreadLocal.get(); }
从源码可以看到,myLooper方法实际上是ThreadLocal调用了get方法。而ThreadLocal在安卓版本中API28以下是对Jdk中ThreadLocal进行修改的。API28又使用了JDK中的。以下根据API28 ThreadLocal.get()源码。
public T get() { Thread t = Thread.currentThread(); //获取当前线程 ThreadLocalMap map = getMap(t); //获取当前线程Thread对象中ThreadLocalMap对象 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); //获取该ThreadLocal在Thread中的 Entry if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; //如果有值,则返回ThreadLocal中保存的对象 } } //如果没值,则调初始化方法,则调用ThreadLocal对象initialValue方法,创建泛型对象, //将该ThreadLocal中将该对象存入ThreadLocalMap中 return setInitialValue(); }
private T setInitialValue() { T value = initialValue(); //创建泛型对象, Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) // 以ThreadLocal对象为键,ThreadLocal对应的泛型对象为值存储到Thread.ThreadLocalMap中 map.set(this, value); else createMap(t, value); return value; }
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
以上源码分析则可以知道,一个线程Thread对象,则只有一个Looper对象,因为sThreadLocal变量为Looper的静态成员变量,而Looper公开的创建方法只能调用Looper.prepare():源码如下。
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"); } //当线程中的Looper对象为空,则存入一个Looper对象 sThreadLocal.set(new Looper(quitAllowed)); }
3:以上了解了Looper对象创建的原理,以及与线程的关系,那么我们的主函数Looper对象是在哪调用的。实际上是在ActivityThread类中main方法中调用。当我们点击桌面图标,则由系统launcher启动我们的APP,则交给ActivityManagerService来处理,如果我们APP没启动,则新建进程,并执行ActivityThread类中main方法。以下是源码:
public static void main(String[] args) { //省略 Looper.prepareMainLooper(); //省略 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
则主线程调用Looper.loop();之后会无限循环,以下是源码:
public static void loop() {
final Looper me = myLooper();
//省略
for (;;) {
Message msg = queue.next(); //获取到Message
//省略
try {
//调用该Message对应的 hanler 的dispatchMessage方法,内部调用handleMessage方法
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略
}
}
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//当有定时消息处理,则处于阻塞状态,可通过sendMessage调用enqueueMessage方法中nativeWake(mPtr)来唤醒
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
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;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
4:接下来看Handler发送消息.
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
最终走到以下方法调用 queue.enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
继续跟踪MessageQueue.enqueueMessage方法源码
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) { 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; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
对于以上,我的理解是:当发送消息,则按照消息定时的顺序由小到大重新排列消息,如果需要唤醒Looper轮询的MessageQueue中next方法里的nativePollOnce(ptr, nextPollTimeoutMillis),则nativeWake(mPtr);唤醒。所以我们发的消息就可以在指定的线程绑定的Looper里执行了。至于已经处于阻塞状态,如何发消息,那肯定是其他线程发的。
总结:Handler发消息需要的元素:
1:Hander 处理与发送消息。
2:Message 发送的消息,内部target属性绑定该Hander
3:MessageQueue 发送的消息存在该队列。
4:Looper 轮询消息队列,获取到消息时,调用该消息绑定的Hander处理消息。