handler浅析
-
基本概念
handler在创建的时候,就会和当前创建它的线程所绑定。一个线程可以有多个handler,但是只能有一个looper对象和MessageQueue
熟悉Windows编程的朋友知道Windows程序是消息驱动的,并且有全局的消息循环系统。Google参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。Android通过Looper、Handler来实现消息循环机制。Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。
Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
官方解释
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的交互
一个线程里只能有一个looper对象,消息的循环,一定需要looper,而UI主线程里的looper对象是默认绑定的,其他线程则需要自己来绑定,否则会报错。
官方解释
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()里会检测当前线程中是否有looper对象,有会报错( throw new RuntimeException("Only one Looper may be created per thread");),没有则创建。而在loop()里,则会得到当前looper的queue,执行消息循环
源代码
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));
}
构造方法
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();
}
}
-
总结
- handler在创建时和线程绑定
- 每个线程里面只有一个looper和MessageQueue,可以有多个handler。
- 主线程(UI线程)的looper对象在activity创建时,Looper和MessageQueue在ActivityThread.main时已经创建好。
- 其他线程(非主线程),想要使用消息循环,必须使用Looper.prepair()以及Looper.loop()
hanlder虽然是绑定线程的,但是可以在其他线程中使用这个handler,利用这个handler传递消息,当然这个消息就到了创建这个handler的线程里了。looper是线程安全。如图:
这2个handler属于UI线程