在使用线程创建Handler进行消息处理时,会使用如:
new Thread(){
@Override
public void run() {
Looper.prepare();
handlerthread = new myHandler() {
@Override
public void handleMessage(Message msg) {
System.out.println("thread handle : "+msg.obj);
...
}
};
Looper.loop();
}
}.start();
使用
Looper.prepare();
处理handleMessage业务逻辑
Looper.loop();
的方式来处理数据、更新UI。
而为什么可以在线程处理Handler数据,Looper又是干什么的,在整个消息处理的流程是怎么样的?接下来我们来分析一下。
1.初始化
Looper.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));
}
分析ThreadLocal类在这篇文章中,介绍了ThreadLocal类的作用,这里不细说,简单就是存放了一个Looper对象,在该线程的某个时刻取出来使用。所以,一个线程只有一个Looper实例。
我们来看看new Looper()做的事情。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在这里,Looper的实例创建了MessageQueue对象,保存了当前的线程。
Looper.loop()
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final long end;
try {
msg.target.dispatchMessage(msg);
} finally {
}
msg.recycleUnchecked();
}
}
这里保留核心的逻辑。看一下myLooper(),就是获得前面prepare()方法里新创建的Looper对象。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
再获取Looper里面的MessageQueue。接着for循环处理消息队列里面的消息。其中源码注释了might block没消息时会进行阻塞(涉及到Linux pipe/epoll机制,不细讲)。
处理数据能猜到,就是msg.target.dispatchMessage(msg)方法。
msg.target为Handler类型,所以实际是调用Handler.dispatchMessage方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里能看到,handleMessage就是我们一开始例子里面我们重写的Handler方法,就是我们要实现的业务逻辑。
到这一步我们可以整理一下Handler、Looper、Message的关系,如下图:
2.发送消息
那我们是怎么样把Message插入到MessageQueue里面呢?我们来看一下调用流程:
通常我们都是调用Handler实例.sendMessage() 、sendEmptyMessage() 、post()等方法,
实际都是调用MessageQueue.enqueueMessage()方法,源码如下:
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
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;
}
for循环可以看出,找到消息队列的最后一个,把要处理的消息插入到队列最后。
我们来整理一下整个执行的流程。
1.初始化:
Looper.prepare();
调用sThreadLocal.set(new Looper(quitAllowed))方法。实例化Looper类,保存在线程的ThreadLocalMap中。
Looper.loop();
Looper me = myLooper(); 获取Looper.prepare()方法生成的Looper。
for循环,遍历MessageQueue,等待消息插入队列,无消息时可能会被挂起。
2.发送消息:
Handler.post()、Handler.sendMessage()、Handler.sendEmptyMessage()
最后调用函数enqueueMessage(queue, msg, uptimeMillis),添加msg到MessageQueue
3.执行消息:
msg.target.dispatchMessage(msg);
handleMessage(msg);执行自己添加的业务逻辑
最后,我们来看一开始提出的问题:
为什么可以在线程处理Handler数据?
因为在Looper初始化时,已经绑定了当前调用的线程,只要往消息队列放数据,在loop()方法的循环都能处理。
Looper又是干什么的?
从前面对应关系图可以看到,作用有
1.存放MessageQueue
2.绑定当前调用线程
3.Loop()方法负责循环处理消息
在整个消息处理的流程是怎么样的?
处理流程按照前面所讲的,Looper初始化后,发送消息时放入消息队列,在loop()方法取出处理。
这里再扩展一个问题,为什么在主线程调用的Handler实例不需要Looper呢?
因为Android程序入口点Android.app.ActivityThread的main()方法里,也调用了Looper.prepareMainLooper和Looper.loop()。