Handler、Message、MessageQueue、Looper
1.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 sThreadLocal.set(new Looper(quitAllowed)); }
private Looper(boolean quitAllowed) { //这里创建的MessageQueue mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
平时我们在主线程和子线程之间切换没调用Looper.prepare();是因为Activity创建的时候已经调用过Looper.prepareMainLooper();
2.Looper.loop();
public static void loop() {
final Looper me = myLooper();
if (me == null) {
//这个错误很多人应该见过,是因为没有调用Looper.perpare()就调用Looper.loop()
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//这里是个死循环
for (;;) {
//这里获取到Message
Message msg = queue.next();
//当msg为null才会退出,调用quit方法退出时会在消息队列里加入一个null的msg
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...此处省略代码
try {
//msg.target 就是发送消息的Handler,调回到Handler的dispatchMessage方法里了
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...此处省略代码
}}
3.Message
好像没啥说的,或者不知道怎么说。。。。
While the constructor of Message is public, the best way to get * one of these is to call {@link #obtain Message.obtain()} or one of the * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull * them from a pool of recycled objects.
这里是官方的注释,官方建议使用Message.obtain()方法来获取Message
4.new Handler()
//最常用的构造方法
public Handler() { this(null, false);}
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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
//这个错都见过吧?就是因为没有调用Looper.prepare()
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
5.handler.sendMessage()
//方法调用
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//将Handler放入target里,后面消息分发时就会使用msg.target.dispatchMessage(msg);
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//将消息加入消息队列中
return queue.enqueueMessage(msg, uptimeMillis);
}
以常用的子线程向主线程发送消息为例,梳理下逻辑
- Activity初始化时帮我们调用的了Looper.prepare(),这里创建了Looper和MessageQueue
- Activity初始化时也帮我们调用了Looper.loop(),进入死循环一直在调用queue.next()获取消息
- 发送消息,最终通过queue.enqueueMessage(msg, uptimeMillis); 将消息加入消息队列中
- 死循环中获取到刚刚发送的消息通过queue.next(); 方法获取到消息
- 获取到消息通过msg.target.dispatchMessage(msg);分发到Handler
扯了半天,怎么切换的线程?
这里依靠的是ThreadLocal,简单的说它只属于自己的线程,即使是同一个ThreadLocal对象,也可以在不同的线程中获取到不同的值,想专门了解这个的可以自行查找,这里不做长篇叙述。
Looper类中有
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();在Looper.perpare()中
sThreadLocal.set(new Looper(quitAllowed));
还是以子线程向主线程发送消息为例
此时的Looper.perpare()和Looper.loop()都还是在主线程也就是UI线程中被调用,因为是Activity初始化时已经帮我们调用了Looper.perpare()和Looper.loop(),所以不需要我们手动调用了。
向主线程发送消息,所以我们的Handler要创建在主线程里,在上面Hnadler的构造方法里有
mLooper = Looper.myLooper();
因为上述介绍到ThreadLocal的特性,同在主线程中,所以获取到的即为在Looper.perpare()中创建的Looper对象
在子线程中发送消息出去,消息被放入消息队列中,Looper对象是相同的,而所使用的消息队列是Looper对象的私有属性,也没有发生变化,所以MessgeQueue也是相同的,之在Looper.loop()方法中发送的消息通过queue.next()方法被获取到,在Looper.loop()方法中调用了 msg.target.dispatchMessage(msg)方法,而Looper.loop()方法是在主线程中调用的,所以最终Handler中的dispatchMessage方法就是在主线程中调用的了。