我们知道子线程发送消息给主线程是使用Handler的,基本用法就是在主线程中创建Handler、在子线程通过handler.sendMessage()发送消息、handlerMessage()中处理消息。但是这之间的具体过程可能很多人不清楚,其实就是通过Looper来无限循环处理消息的,Looper也可以称为轮询器。
UI线程的Looper是在ActivityThread->main()方法中创建的,也就是说UI线程的Looper是默认创建的,不需要我们自己操作,同时这个main函数也是APP的入口。我们看下源码:
public static void main(String[] args) {
...
Looper.prepareMainLooper();//创建主线程的Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();//获取主线程的Handler
}
Looper.loop();//开始消息循环,这是一个死循环,后面会讲到
}
Looper.prepareMainLooper()就是在主线程中创建Looper并将其添加到sThreadLocal中,sThreadLocal的作用就是使得不同的线程不能访问别的线程的消息队列
public static void prepareMainLooper() {
prepare(false);//创建Looper,false的作用是指定此线程不能被终止
synchronized (Looper.class) {
...
sMainLooper = myLooper();//myLooper()方法通过sThreadLocal.get()获取创建的Looper,并赋给sMainLooper(主线程的Looper)
}
}
private static void prepare(boolean quitAllowed) {
...
sThreadLocal.set(new Looper(quitAllowed));//创建Looper并将其添加到sThreadLocal中
}
创建Looper对象时,会同时创建MessageQueue,
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
现在主线程Looper和MessageQueue都创建好了,但是怎么发送和处理消息呢?答案就是使用Handle处理,我们先看下Handler的构造函数:
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();//获取Handler所处线程的Looper,mLooper为空则抛出下述异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//获取消息队列
mCallback = callback;
}
从上述代码可以看出Handler创建时会关联其所处线程的Looper和MessageQueue,所以当子线程需要发送消息给主线程时,Handler必须在主线程中创建,这样handlerMessage()才会在主线程执行。
主线程若发消息给子线程,则Handler需在子线程中创建,但是前提子线程必须要自己创建好Looper和MessageQueue,否则就会抛出上述异常。
现在理清了Handler与Looper和MessageQueue的关系,我们还得知道怎么发送和处理消息。
我们知道创建Handler是必须要实现handlerMessage()方法,如下所示:
class MyHandler extends Handler {
@Override
public void handlerMessage(Message msg) {
//更新UI
}
}
也就是说我们发出的消息最终会被handlerMessage()方法处理,但是handlerMessage()是怎么被调用的呢?其实就是当我们执行Handler.sendMessage()或mHandler.post()等方法发送Message时,最终都是调用sendMessageAtTime()方法,这个方法将Message添加到MessageQueue中。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//获取MessageQueue
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);//将Message添加到MessageQueue中
}
前面讲了Looper.loop()方法时无限循环的,只有消息队列中有消息就会被处理。
public static void loop() {
final Looper me = myLooper();//获取Looper
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;
}
msg.target.dispatchMessage(msg);//处理消息,msg.target是目标Handler
msg.recycleUnchecked();//回收消息
}
}
注意,每个Message都有一个target变量,用于指向处理消息对应的Handler,因为一个线程可能有多个Handler,通过target来区分。
从上面代码可以看出处理消息实际上是调用Handler的dispatchMessage()方法,而dispatchMessage()方法就是调用handlerMessage()处理消息。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//处理消息
}
}
总结一下:主线程会默认创建Looper,然后new Looper()时会创建MessageQueue,子线程发消息给主线程的过程是:在主线程创建Handler对象,在子线程通过Handler.sendMessage()等方法发送消息,此消息被添加到handler对象所在线程的MessageQueue中,然后Looper.loop()无限循环地从MessageQueue中取消息并且调用Handler的dispatchMessage()方法将消息发送给handleMessage()处理。我们可以在handleMessage()方法中更新UI等。
若需要主线程发消息给子线程,则Handler需在子线程中创建,但是前提子线程必须要自己创建好Looper和MessageQueue,否则就会抛出异常。可以参考下述示例:
new Thread {
Handler handler = null;
public void run() {
Looper.prepare();//创建此线程的Looper
handler = new Handler();
Looper.loop();//启动消息循环
};
}.start();