Handler
-
Handler的声明:
Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { return false; } });
其中构造方法可以不传参数,可以像上面一样传入Handler.Callback,也可以传入Looper
-
使用:
handler.post(new Runnable() { @Override public void run() { Log.d(TAG, "run: currentThread:"+Thread.currentThread()); } });
这里打印的线程是主线程
还可以使用hander.sendMessage等一系列方法,这种方式会回调创建匿名类中的handleMessage方法中。
-
不管是post还是sendMessage,最终都会调用到Handler的
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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
可以发现是往queue消息队列中加入了一条消息!!!
-
那么当有消息来的时候,Looper会调用Handler的
dispatchMessage
方法:public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
其中msg.callback是我们post方法传入的runnable对象。
mCallback是创建Handler的时候传入的Callback对象。
所以我们发送消息时候会回调我们实现的Callback中的handleMessage方法。
最后的handleMessage方法是一个空方法。
MessageQueue
MessageQueue是消息队列,但是内部实现为单链表,主要是通过next
方法取消息,并将消息移出队列。next
方法中是一个无限的循环,如果没有消息,将会阻塞。
enqueueMessage
方法用于插入消息到队列之中。
Looper
looper是消息循环,不断的从MessageQueue中查看是否有新消息,如果有就立刻处理,如果没有就阻塞。
在子线程中创建一个Looper:
new Thread("Thread #2"){
@Override
public void run() {
Looper.prepare(); #为当前线程创建一个Looper
Handler handler = new Handler();
Looper.loop(); #开启消息循环 会阻塞线程
}
}.start();
Looper的prepare
方法会转到另一个重载方法,将Looper对象加入sThreadLocal:
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));
}
sThreadLocal声明如下,泛型是Looper:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
然后new Handler()
最终会转到这个构造方法:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
其中的Looper.myLooper()
的方法实现如下:
public static Looper myLooper() {
return sThreadLocal.get();
}
所以,如果在子线程中没有调用Looper.prepare()
,那么sThreadLocal
里面保存的就会为空,那么会抛出运行时异常:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
接下来看看loop
方法:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block 可能阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);//分发消息
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
可以看到loop方法里面有一个无限的循环,一直向queue消息队列获取消息,如果没有消息,那么会阻塞,有了消息之后会调用msg.target.dispatchMessage(msg);
分发消息,msg.target就是Handler对象,这个在一开始就分析了Handler分发消息的过程。