1 一个线程能否创建多个Handler,Handler跟Looper之间的对应关系 ?
一个线程能够创建多个Handler,Handler跟Looper没有对应关系,线程才跟Looper有对应关系,一个线程对应着一个Looper,如下所示:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将Looper存到当前线程的ThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}
创建Handler时,需要先调用Looper的prepare方法,在该方法中,会首先判断sThreadLocal.get()是否为空,如果不为空就抛出异常,内容是:一个线程只能创建一个Looper。如果sThreadLocal.get()为空,则会创建一个Looper对象并存入sThreadLocal中。
创建多个Handler方式如下:
Looper.prepare();
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Handler handler1 = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
上述代码并不是最完美的代码,没有考虑内存泄漏,代码规范等,只是简单的为了说明该如何使用而已。在主线程中,我们只需要创建Handler就行,不需要调用Looper.prepare()和Looper.loop(),因为在android应用启动时,主线程已经调用了Looper.prepareMainLooper方法帮我们创建了Looper对象,因此不需要我们再自己重新创建。有人会问,那么我们如何知道哪条消息是哪个handler发送的呢?Looper取出消息又如何发送到指定的Handler呢?
2 Looper取出消息又如何发送到指定的Handler呢?
上述我们说到,一个线程对应一个Looper,可以对应多个Handler,这里的Looper和handler都属于同一个线程。而每个线程都有一个属于自己的ThreadLocal,Looper对象就存储在线程的ThreadLocal中(如上述代码所示)。从handler发送消息,最终会调用Handler类中的enqueueMessage方法,该方法源码如下所示:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
我们看该方法的第一句
msg.target = this;
我们可以看下Message类中的target是什么
/*package*/ Handler target;
可以看到该target是一个Handler类型,所以msg的target指向了当前Handler对象,然后msg被加入到消息队列,通过调用下面代码
queue.enqueueMessage(msg, uptimeMillis);
消息存入消息队列后,就会唤醒Looper,然后Looper就会从loop方法中获取消息,如下所示:
public static void loop() {
final Looper me = myLooper();
......
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
me就是线程中prepare方法里创建的Looper对象,该Looper对象里有个消息队列,如下方法获取消息队列
final MessageQueue queue = me.mQueue;
该消息队列中存储着通过handler发送过来的Message,而MessageQueue通过下列方法从消息队列中取出消息
public static void loop() {
......
for (;;) {
Message msg = queue.next(); // might block
......
}
该消息中封装着发送消息的handler对象,取出消息后,就会通过dispatchMessage方法将消息分发出去,如下所示:
msg.target.dispatchMessage(msg);
这句的意思就是将msg发送到指定的Handler中。
3 总结
- 一个线程可以创建多个Handler,但只能创建一个Looper,一个MessageQueue。Handler跟Looper之间没有对应关系
- Handler通过sendMessage发送消息时,就会将handler对象存储到message中,然后Looper在loop中通过MessageQueue的next方法取出消息后,会通过之前消息封装的handler将消息发送到指定的handler,即通过调用msg.target.dispatchMessage方法。
网友评论