一、引言
Android开发中总是免不了处理一些耗时的操作,如网络请求、IO文件读写等等,都需要用子线程来处理,耗时操作往往也伴随着更新UI的显示。此时就涉及到UI线程与子线程之间的通信问题。为此Android系统引入了Handler异步消息处理的机制。
二、在子线程中更新UI
Android中想要在子线程中更新UI,通常有三种办法:
- Handler的post方法
- View视图控件的post方法
- Activity的runOnUiThread()方法
Handler的post方法,应该都很清楚,内部的Runnable的run方法已经是在UI线程执行了。View的post方法、Activity的runOnUiThread()方法怎么也可以在UI线程呢,来看看其内部实现:
// View.java
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
// Activity.java
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
很显然从源码可以看出最终都是交给主线程Handler的post方法来处理。那么为什么主线程声明实例化的Handler的post方法在子线程调用就可以用来更新UI呢?这个问题暂时先放这里。接下来进一步分析Handler。
三、Handler的消息处理机制
在Handler的消息处理架构中,和Message、MessageQueue、Looper这三个类是紧密相连的。
Message:消息数据承载类,可以是事件任务消息,也可以是其它的实体数据消息。
MessageQueue:消息队列。用于将消息入队和出队,以及消息从队列删除释放的管理。
Looper:消息循环处理器。用于维持一个死循环不断的从MessageQueue中取出消息,并将消息分发给设置的目标对象处理(target即Handler)。
Handler:它是整个机制的辅助类。也是提供给客户端使用对外暴露Api。用于辅助把消息加入队列、删除释放消息事件和消息的回调处理。
Handler中我们最常用的有post()、postDelay()、sendMessage()等方法,直接或者间接的在内部构建一个Message消息对象然后通过MQ(MessageQueue)的enqueueMessage来处理消息入队的工作。App启动的时候在ActivityThread类的main方法里就先通过prepareMainLooper方法预加载了一个Looper对象,然后通过loop方法开启了消息循环器。
// ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
...
}
以上的Looper对象是主线程的,因此构造的MQ消息队列也是主线程的,loop()方法中不断循环取出队列中的消息,通过handler的dispatchMessage方法分发消息。当然从一个事件消息的发送入队到出队处理回调不一定是实时的,MQ的enqueueMessage和next方法可以看出它是一个单向链表队列,入队的时候根据消息发送的时间when按升序排序,当when为0时插入到队列头部。