在阅读该篇文章之前要清楚的一些知识点:
- 一个线程之中可以有多个
Handler
,但是每个线程之中只有一个Looper
和一个MessageQueue
- 消息队列
MessageQueue
是在Looper
中进行创建的,Handler
的作用是往MessageQueue
中发送消息和处理消息的- 在子线程中如果要创建
Handler
对象,必须先调用Looper.prepare()
方法创建Looper
对象和MessageQueue
- 在什么线程中创建
Handler
,那么该Handler
就持有该线程的Looper
和MessageQueue
,例如在主线程中创建Handler
就可以更新UI界面就是因为这个
官方说明
Handler允许你发送和处理Message消息,每个Handler的实例都与一个线程和该线程中的消息队列(MessageQueue)关联,当你创建一个新的Handler时,它就绑定到了正在创建它的线程(消息队列),然后就可以通过该Handler将Message和runnables发送到该消息队列,并在消息出来时执行他们。
Handler有两个用途:
- 安排消息(Message)和runnables在将来的某个时刻执行
- 线程之间的通信
往消息队列中发送消息可以通过
- post(Runnable)
- postAtTime(java.lang.Runnable, long)
- postDelayed(Runnable, Object, long)
- sendEmptyMessage(int)
- sendMessage(Message)
- sendMessageAtTime(Message, long)
- sendMessageDelayed(Message, long)
为应用程序创建进程时,主线程创建消息队列,该队列负责管理*应用程序对象(活动,广播接收器等)及其创建的任何窗口。您可以创建自己的线程,并通过Handler与主应用程序线程进行通信。这是通过调用与以前相同的post或sendMessage方法完成的。然后,将在Handler的消息队列中调度给定的Runnable或Message,并在适当时进行处理。
MessageQueue
官方文档中多次提到了MessageQueue这个消息队列,那么该消息队列什么时候创建的,Handler怎么发送消息到MessageQueue中的,以及怎么处理这些消息的?下面通过源码的方式梳理这个流程.
1、创建MessageQueue
MessageQueue的创建不需要我们自己去创建,而是通过创建Looper的时候自动创建的,代码如下:
private Looper(boolean quitAllowed) {
//在Looper的构造方法中,创建了MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
复制代码
由于该构造方法是私有的,所以提供了静态方法prepare()
来创建Looper,然后通过myLooper()
方法来获取Looper对象,这要是为什么我们在子线程中创建Handler的时候要先调用prepare()
方法的原因。
2、Handler发送消息到MessageQueue中
通过调用Handler的 post
sendMessage
等方法可以将消息发送到MessageQueue中,具体中间经历了什么,所有的post
方法和sendMessage
方法,最终调用的都是sendMessageAtTime
方法可以看一下源代码:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//获取到消息队列,消息队列是在Handler的构造方法中获取到的
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);
}
复制代码
在创建Handler的时候,构造方法中会获取当前线程的Looper,然后通过Looper获取到MessageQueue.
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//获取该线程的Looper对象,Looper对象是放在ThreadLocal对象中的,保证每个线程只有一个Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//获取了消息队列,在sendMessage和post的最后都是往队列中插入消息
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
复制代码
3、处理消息
首先我们要弄明白是谁来进行处理消息的,我们一般创建Handler的时候会重写一个方法handleMessage
, 如果是通过post(Runnable run)
的方法发送的消息,处理是在handleCallback
的方法中,不需要自己去实现。
那么是什么时候调用的handleMessage
方法呢?
- 应用启动之后,主线程开启Looper循环,调用
Looper.loop()
方法开启死循环,该循环中就是从MessageQueue中取消息来处理,如果没有消息了会阻塞。释放CPU资源
public static void loop() {
final Looper me = myLooper();
//...省略部分代码...
//开启死循环
for (;;) {
//从消息队列中获取Message,该方法会阻塞,如果队列中没有消息,则阻塞,释放CPU资源
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...省略部分代码...
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//target就是这个消息是哪一个Handler发送的,target就是那个Handler对象,
//调用Handler的dispatchMessage方法来派发消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...省略部分代码...
//消息回收
msg.recycleUnchecked();
}
}
复制代码
- 从
loop()
方法中找到了消息发送到MessageQueue的时候,Looper会从消息队列中获取到消息,然后通过消息中的target
字段获取到消息所属的Handler
,然后调用Handler
的dispatchMessage
来进行处理。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
复制代码
从上面的方法中可以看到,如果callback
不为空,就直接执行handlerCallback
,callback
其实就是一个Runnable
, handleCallback
方法就是调用run())
方法来使其运行。 如果callback
为空的情况下就是通过handleMessage
来进行处理消息了。所以我们在创建了Handler
的时候要重写该方法进行一些操作
总结
以上基本上就是Handler
的一些流程说明了,现在我们很少用到Handler
,但是很多线程的切换底层还是用到的Handler
, 这是基础。所以还是需要了解一下。文中也有说明了Looper
Handler
和MessageQueue
之间的关系,还有什么疑问可以留言,如看到一定回解答。感谢阅读????