Handler原理是该系列的最后一篇文章,Handler在Android的体系中有这个举足轻重的分量,在跨进程通信,跨线程通信等都有着它的身影。
该系列的其他文章
- Handler消息机制(一)Message复用原理
- Handler消息机制(二)ThreadLocal原理
- Handler消息机制(三)MessageQueue原理
- Handler消息机制(四)Looper原理
本文主要从以下几个部分对Handler进行分析,
- Handler是什么?
- Handler如何使用?
- Handler的工具系列方法?
1. Handler是什么?
官方描述: A Handler allows you to send and process {@link Message} and Runnable objects associated with a thread's {@link 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. Handler可以发送和处理与线程关联的Message和Runable对象。 每个Handler实例都与一个线程和该线程的消息队列关联。 创建新的Handler时,它可以绑定到创建该Handler的线程上和该线程下的消息队列中,Handler会把消息和Runable传递到线程内的队列中,并再队列内的消息被读取出处理该消息。
通过官方描述,我们可以很清楚的知道Handler的职责,会关联到对应的线程,然后往线程内的消息队列发送定时的消息或者可执行的Runable对象,最后会处理消息。
2. Handler如何使用?
主要看下Handler的构造方法,Handler提供了7种构造方法,但最终只有两个是实际构造Handler的方法。 这两个的主要区别是:构造方法内传入Looper关联线程和主动通过getLooper去获取当前线程的Looper。 主动获取Looper的构造方法:
public Handler(Callback callback, boolean async) {
// 主动查询当前创建Handler的线程内的Looper对象,UI线程内创建的Handler最终会调用
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 记录当前线程下的消息队列
mQueue = mLooper.mQueue;
mCallback = callback;
// 异步标志,如果为true,传入的消息均是异步消息,默认为false
mAsynchronous = async;
}
参数传入Looper的构造方法:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
// 记录当前线程下的消息队列
mQueue = looper.mQueue;
mCallback = callback;
// 异步标志,如果为true,传入的消息均是异步消息,默认为false
mAsynchronous = async;
}
UI线程下使用Handler:
Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case MSG_1:
test1();
break;
case MSG_2:
test2();
break;
default:
super.handleMessage(msg);
break;
}
}
};
// 向队列中插入消息
Message msg = mHandler.obtainMessage(MSG_1);
// msg的其他信息
...
mHandler.sendMessage(msg);
简单使用方式如上,非常简单,这里就不做过多介绍了。
3. Handler的工具系列方法?
3.1 obtain方法
在Handler中有提供了一系列的obtain方法,在obtain系列方法内是通过Message.obtain()方法来获取Message对象,我这里说获取是因为在obtain方法是复用的message对象,如果Message对象池中有message,则直接从池中获取,如果池中为null时,则会创建新的Message对象。详细可以看我之前分析的Handler消息机制(一)Message复用原理
3.2发送消息方法
Handler内send前缀的发送消息的方法有7种,post前缀的方法有5种。 在这些众多的方法中我们各取一个: sendMessageAtTime方法:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
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);
}
sendMessageAtTime方法内部直接调用了enqueueMessage方法。 postAtTime方法:
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
postAtTime方法将Runable对象包装成一个message对象然后调用了sendMessageAtTime,最终一样是到enqueueMessage方法中。 这里我们看下getPostMessage方法,是通过Message.obtain()来获取message对象,然后将r赋值给msg内的callback。
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
根据上面的分析,send和post系列方法最后都会调用到enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 将Handler自己赋值给target
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在enqueueMessage方法中,我们看到msg.target被赋值成Handler对象自身,在消息被读取时,是通过msg.target.dispatchMessage被分配到各个消息被处理的地方。这就是为什么同一个线程下,有多个Handler时可以分别处理对应Handler自身定义的消息。接着看mAsynchronous变量,这个是在构造Handler方法时设置的,默认为false,当该值被置为true时,msg会setAsynchronous操作,该方法会把消息对象设置成异步消息。在分析MessageQueue时,我们知道当队列有同步屏障时,会优先处理异步消息。最后是通过queue的enqueueMessage方法将消息放入MessageQueue队列中。MessageQueue相关的知识可以参考Handler消息机制(三)MessageQueue原理。
3.3 removeMessage方法
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
将MessageQueue中记录的消息删除。
3.4 dispatchMessage方法
public void dispatchMessage(Message msg) {
// callback是Runable对象
if (msg.callback != null) {
handleCallback(msg);
} else {
// Handler构造方法设置的Callback,默认为null
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 空方法,用户自行实现
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
// Runable接口内的run方法
message.callback.run();
}
在Looper原理那一篇中,loop方法内有一段代码"msg.target.dispatchMessage(msg);",这段代码会把读取的消息分配到处理该消息的Handler对象内,在dispatchMessage方法中主要有三个回调方法。 以上就是具体一个消息被分配到指定的Handler中的处理过程。 当消息是通过post方式入队的,则只能由Runable实现的接口被回调。 当消息是send方式入队的,则可以在mCallback.handlerMessage()handleMessage()处理。
结语:Handler是Handler机制中的终端处理模块也是消息发送模块,是我们在Handler机制中接触最频繁的一个模块,希望各位朋友在阅读了该系列文章之后能够对Handler消息机制有一个清晰的认识。