handler淺析
-
基本概念
handler在創(chuàng)建的時(shí)候,就會(huì)和當(dāng)前創(chuàng)建它的線程所綁定。一個(gè)線程可以有多個(gè)handler,但是只能有一個(gè)looper對(duì)象和MessageQueue
熟悉Windows編程的朋友知道Windows程序是消息驅(qū)動(dòng)的,并且有全局的消息循環(huán)系統(tǒng)。Google參考了Windows的消息循環(huán)機(jī)制,也在Android系統(tǒng)中實(shí)現(xiàn)了消息循環(huán)機(jī)制。Android通過(guò)Looper、Handler來(lái)實(shí)現(xiàn)消息循環(huán)機(jī)制。Android的消息循環(huán)是針對(duì)線程的,每個(gè)線程都可以有自己的消息隊(duì)列和消息循環(huán)。
Android系統(tǒng)中的Looper負(fù)責(zé)管理線程的消息隊(duì)列和消息循環(huán)。通過(guò)Looper.myLooper()得到當(dāng)前線程的Looper對(duì)象,通過(guò)Looper.getMainLooper()得到當(dāng)前進(jìn)程的主線程的Looper對(duì)象。
官方解釋
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. ==When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it== -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
源碼
private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
Thread currentThread = Thread.currentThread();
if (group == null) {
group = currentThread.getThreadGroup();
}
if (group.isDestroyed()) {
throw new IllegalThreadStateException("Group already destroyed");
}
this.group = group;
synchronized (Thread.class) {
id = ++Thread.count;
}
if (threadName == null) {
this.name = "Thread-" + id;
} else {
this.name = threadName;
}
this.target = runnable;
this.stackSize = stackSize;
this.priority = currentThread.getPriority();
this.contextClassLoader = currentThread.contextClassLoader;
// Transfer over InheritableThreadLocals.
if (currentThread.inheritableValues != null) {
inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);
}
// add ourselves to our ThreadGroup of choice
this.group.addThread(this);
}
-
與looper的交互
一個(gè)線程里只能有一個(gè)looper對(duì)象,消息的循環(huán),一定需要looper,而UI主線程里的looper對(duì)象是默認(rèn)綁定的,其他線程則需要自己來(lái)綁定,否則會(huì)報(bào)錯(cuò)。
官方解釋
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
prepare()里會(huì)檢測(cè)當(dāng)前線程中是否有l(wèi)ooper對(duì)象,有會(huì)報(bào)錯(cuò)( throw new RuntimeException("Only one Looper may be created per thread");),沒(méi)有則創(chuàng)建。而在loop()里,則會(huì)得到當(dāng)前l(fā)ooper的queue,執(zhí)行消息循環(huán)
源代碼
prepare()
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));
}
構(gòu)造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
loop()
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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();
}
}
-
總結(jié)
- handler在創(chuàng)建時(shí)和線程綁定
- 每個(gè)線程里面只有一個(gè)looper和MessageQueue,可以有多個(gè)handler。
- 主線程(UI線程)的looper對(duì)象在activity創(chuàng)建時(shí),Looper和MessageQueue在ActivityThread.main時(shí)已經(jīng)創(chuàng)建好。
- 其他線程(非主線程),想要使用消息循環(huán),必須使用Looper.prepair()以及Looper.loop()
hanlder雖然是綁定線程的,但是可以在其他線程中使用這個(gè)handler,利用這個(gè)handler傳遞消息,當(dāng)然這個(gè)消息就到了創(chuàng)建這個(gè)handler的線程里了。looper是線程安全。如圖:

這2個(gè)handler屬于UI線程