handler的工作流程
1、异步通信准备
系统通过调用Looper.prepare()为线程准备Looper和承接Message的MessageQueue;
2、消息入队
用户通过Handler.sendMessage这一类的函数调用,向MessageQueue里面不断的发送消息;
3、消息循环
系统调用Looper.loop()函数,这个函数会开启一个死循环,在循环中不断的轮询MessageQueue消息队列,从消息队列中取出可以执行的Message消息,然后进行执行。
4、消息处理
Looper中的loop不断的轮询MessageQueue,一旦发现MessageQueue里面有可执行的消息,那么就会将消息取出来,然后通过消息所携带的handler去执行。
源码解析
A线程创建一个handler
Thread hanMeiMeiThread = new Thread() {
@Override
public void run() {
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "hanMeiMei receiver message: " + ((String) msg.obj));
Toast.makeText(MainActivity.this, ((String) msg.obj), Toast.LENGTH_SHORT).show();
}
};
Looper.loop();
}
};
若A为主线程,创建handler无需调用Looper.prepare()和Looper.loop(),具体代码如下:
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_WHAT:
Log.d(TAG, "main thread receiver message: " + ((String) msg.obj));
break;
}
}
};
因为在主线程中,App初始化的时候都会执行ActivityThread的main方法,main方法中,已经执行了Looper.prepare()和Looper.loop()。
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
B线程调用该handler
private void sendMessage() {
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// Message msg = new Message();
Message msg = mHandler.obtainMessage(MESSAGE_WHAT);
msg.what = SDK_PAY_FLAG;
msg.obj = "I am message from work thread";
mHandler.sendMessage(msg);
}
};
// 必须异步调用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
那Looper.prepare()和Looper.loop()到底做了什么事呢?我们先来看看Looper.prepare()。
//我们先来看看子线程不调用Looper.prepare()时出错的原因。
//如下是Handler构造函数里抛出上文异常的地方,可以看到,由于mLooper对象为空才抛出的该异常。
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
/*
异常的原因看到了,接下来我们看看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");
}
sThreadLocal.set(new Looper(quitAllowed));
}
/*
可以看到,该方法在当前thread创建了一个Looper(), ThreadLocal主要用于维护线程的本地变量,
*/
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//而Looper的构造函数里面又为我们创建了一个MessageQueue()对象。
接下来看看Looper.loop()做了什么:
public static void loop() {
/*
可以看到,在调用Looper.prepare()之前是不能调用该方法的,不然又得抛出异常了,因为不调用
Looper.prepare(),myLooper()为null。
*/
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback +
": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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();
}
}
/*
这里我们看到,mLooper()方法里我们取出了,当前线程的looper对象,然后从looper对象开启了一个
死循环不断地从looper内的MessageQueue中取出Message,只要有Message对象,就会通过Message的
target调用dispatchMessage去分发消息,通过代码可以看出target就是我们创建的handler。我们在
继续往下分析Message的分发
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/*好了,到这里已经能看清晰了
可以看到,如果我们设置了callback(Runnable对象)的话,则会直接调用handleCallback方法
*/
private static void handleCallback(Message message) {
message.callback.run();
}
//即,如果我们在初始化Handler的时候设置了callback(Runnable)对象,则直接调用run方法。比如我们经常写的runOnUiThread方法:
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
/*
而如果msg.callback为空的话,会直接调用我们的mCallback.handleMessage(msg),即handler的handlerMessage方法。由于Handler对象是在主线程中创建的,
所以handler的handlerMessage方法的执行也会在主线程中。
*/
其实在这里,Looper.prepare()方法主要是创建了一个Looper,再通过Looper.loop()方法,创建了一个死循环,不断的从looper内的MessageQueue中取出Message,只要有Message对象,就会通过Message的target(我们创建的handler)调用dispatchMessage去分发消息,如果设置了callback,就会调用 handleCallback(msg);如果没有设置,就会调用handleMessage(msg);
上面介绍了怎么取message,那Message又是怎么放入MessageQueue中的呢?
我们可以看到,在调用handler时,我们会调用handler的sendMessage方法。
mHandler.sendMessage(msg);
跟踪源码,我们看下sendMessage做了什么:
//调用Handler不同参数方法发送Message最终都会调用到该方法
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);
}
我们可以看到,它又调用了enqueueMessage(queue, msg, uptimeMillis)方法。
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) {
// New head, wake up the event queue if blocked.
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;
}
/*从代码可以看出Message被存入MessageQueue时是将Message存到了上一个Message.next上,
形成了一个链式的列表,同时也保证了Message列表的时序性。
*/
我们可以看到,它被存入MessageQueue时是将Message存到了上一个Message.next上。
消息屏障
handler的消息分为普通消息(同步消息),屏障消息,异步消息。我们通常使用的都是普通消息。
而消息屏障就是在消息队列中插入一个屏障,在屏障之后的所有普通消息都会被挡着,不能被处理。不过异步消息不会被阻挡,所以消息屏障其实就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。
看next的源码:
Message next() {
...
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 阻塞nextPollTimeoutMillis
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//msg.target == null 消息屏障
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 {
// 取出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 {
// No more messages.
nextPollTimeoutMillis = -1;
}
...
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
// 没有要执行的IdleHandler,那么就continue,就会到下一轮循环然后阻塞
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);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
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);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
上面的next方法中,能看到有一个msg!=null&&target==null的判断,这个就是消息屏障。
当target为null的时候,说明就进入了消息屏障,此时会循环查看后面的消息是否是异步消息,如果有,则处理异步消息,如果没有,则循环结束。
为何target==null就是消息屏障?
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
//1、可以看到屏障消息没有设置tartget
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
//2、根据时间顺序将屏障插入到消息链表中适当的位置
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
//3、返回一个序号,通过这个序号可以撤销屏障
return token;
}
}
可以看到当前屏障消息并没有设置target,而普通消息在enqueueMessage中设置了target。由此可以区分是否是屏障消息。
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;// 1.指定目标Handler为当前handler
msg.workSourceUid = ThreadLocalWorkSource.getUid();
// 如果是个异步Handler,那么把消息设为异步消息
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 2. 把msg插入到消息队列中
return queue.enqueueMessage(msg, uptimeMillis);
}
移除屏障消息:
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
//....省略.......
//唤醒线程
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
总结
在使用handler的时候,在handler所创建的线程需要维护一个唯一的Looper对象, 每个线程对应一个Looper,每个线程的Looper通过ThreadLocal来保证,
Looper对象的内部又维护有唯一的一个MessageQueue,所以一个线程可以有多个handler,
但是只能有一个Looper和一个MessageQueue。
Message在MessageQueue不是通过一个列表来存储的,而是将传入的Message存入到了上一个Message的next中,形成一个链式的列表,在取出的时候通过顶部的Message就能按放入的顺序依次取出Message。(优先级队列,先进先出,根据时间顺序排队的单链表)
子线程发送消息到主线程的过程,采用的是优先级队列(priority queue) -> 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。
Looper对象通过loop()方法开启了一个死循环,不断地从looper内的MessageQueue中取出Message,
然后通过handler将消息分发传回handler所在的线程。
//发送消息
Handler.sendMessage(msg)->MessageQueue.sendMessageAtTime(msg,uptimeMills)->MessageQueue.enqueueMessage(msg,uptimeMills)->messageQueue.next = p;
//接收消息
Looper.loop()->messageQueue.next()->dispatchMessage(msg)->handleCallback(msg)/handleMessage(msg);