在阅读该篇文章以前要清楚的一些知识点:html
- 一个线程之中能够有多个
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发送到该消息队列,并在消息出来时执行他们。java
Handler有两个用途:android
往消息队列中发送消息能够经过多线程
为应用程序建立进程时,主线程建立消息队列,该队列负责管理顶级应用程序对象(活动,广播接收器等)及其建立的任何窗口。您能够建立本身的线程,并经过Handler与主应用程序线程进行通讯。这是经过调用与之前相同的post或sendMessage方法完成的。而后,将在Handler的消息队列中调度给定的Runnable或Message,并在适当时进行处理。async
官方文档中屡次提到了MessageQueue这个消息队列,那么该消息队列何时建立的,Handler怎么发送消息到MessageQueue中的,以及怎么处理这些消息的?下面经过源码的方式梳理这个流程.ide
一、建立MessageQueueoop
MessageQueue的建立不须要咱们本身去建立,而是经过建立Looper的时候自动建立的,代码以下:post
private Looper(boolean quitAllowed) {
//在Looper的构造方法中,建立了MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
复制代码
因为该构造方法是私有的,因此提供了静态方法prepare()
来建立Looper,而后经过myLooper()
方法来获取Looper对象,这要是为何咱们在子线程中建立Handler的时候要先调用prepare()
方法的缘由。ui
二、Handler发送消息到MessageQueue中this
经过调用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;
}
复制代码
三、处理消息
首先咱们要弄明白是谁来进行处理消息的,咱们通常建立Handler的时候会重写一个方法handleMessage
, 若是是经过post(Runnable run)
的方法发送的消息,处理是在handleCallback
的方法中,不须要本身去实现。
那么是何时调用的handleMessage
方法呢?
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
之间的关系,还有什么疑问能够留言,如看到必定回解答。感谢阅读🤝