Handler原理浅析
在Android线程相关这篇文章中说到了利用handler实现多线程并通信的方法,于是翻阅了很多博客,也查看了源码,终于从自己的角度理解了handler的原理。于是来梳理一下~
参考:
以线程A为主线程,B为新线程为例:
- A线程通过
Looper.prepare()
创建Looper对象,并初始化其MessageQueue消息队列,此时Looper与线程A绑定。 - A线程中new handler对象,构造函数中绑定Looper对象,同时也绑定了MessageQueue。
- 新建线程B,并执行操作,最后通过A线程中的handler调用
sendMessage()
方法或post()
方法使Message入队Looper中的MessageQueue。 - A线程中的Looper对象通过调用
Looper.loop()
方法使MessageQueue中的Message不断出队,并分发到handler中。 - A线程中的handler的handleMessage方法处理回调。
从源码的角度:
Looper.prepare()
,即初始化Looper对象,及MessageQueue,同时绑定线程(ThreadLocal).static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; 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)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Handler handler = new Handler()
,新建hanlder对象,同时绑定Looper对象及MessageQueue。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) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;
}
新建线程B,在其runnable的run方法中调用线程A的handler的
sendMessage(Message)
或post(Runnable)
方法,这两种方法最后都会调用handler中MessageQueue的enqueueMessage
方法。该方法使Message按时间顺序排列。
`post(Runnable)`方法会新建带有Runnable对象的Message对象,然后在辗转调用`enqueueMessage`方法。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", 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 {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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.loop()
通过死循环使MessageQueue中的Message出队直到队列为空,message.target即为handler的回调。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(); } }
handler重写
handleMessage
方法处理回调,可以看到dispatchMessage
方法即先判断有没有callback,而callback就是handler构造函数中的callback。public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
所以标准的线程通信写法为(可以从Looper的源码中看到):
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}