Handler-MessageQueue-Looper是Android特有的线程间通信机制。
Handler
Handler作为面向开发者的类,每种功能都复写了很多不同的方法,以达到方便开发者调用的目的:
Handler构建
Handler的构造最主要方法如下:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
需要获取一下四个成员变量:
- looper 指定的looper,与线程有关
- messageQueue looper的messageQueue
- callback 可空
- mAsynchronous 是否异步
Handler发送消息
上面的这些方法最终会调用一下方法:
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 将消息的target设为handler对象自己,表示这个消息是handler自己发送的,后面也会根据target的不同,由不同的handler处理消息
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 这里调用messageQueue的enqueue方法将消息加入消息队列
return queue.enqueueMessage(msg, uptimeMillis);
}
这里调用messageQueue的enqueue方法将消息加入消息队列:
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 如果新加入的message立即需要处理或是比队首的消息先处理,那么将消息插入到最前面
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 遍历待处理消息队列,将入队的消息按处理时间顺序插入消息队列中
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
可以看出,将消息插入消息队列分为两种情况:
- 如果当前消息最先需要处理,那么就插入队首
- 如果不是需要最先处理,那么遍历整个队列,按消息需要处理的时间先后顺序插入消息
Handler拿一个未发送的message
obtainMessage最终调用如下方法:
Hanlder.class
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
Message.class
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
最终调用Message类的obtain()方法,Message的obtain()方法通过从Message类中维护的消息池(sPool)中获取之前已经使用过的消息,如果消息池中没有消息,那就返回一个新的消息,这样中可以减少消息对象的创建。
Handler处理消息
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public void handleMessage(Message msg) {
}
这里如果在构造Handler的时候加入了mCallback对象,那会就会执行mCallback对象的handleMessage()方法,否则执行Handler对象的handleMessage()方法。所以在我们写handler代码的时候都回去重写handleMessage(Message msg)方法,来处理handler发送消息。
开发中使用API主要就是以上的部分,下面开始分析,消息的处理机制。
Looper
Looper类在普通的开发中很难使用到,但是它缺少消息机制中重要的一个部分:负责轮询,并分发消息给相应的handler进行处理。
Looper是与线程紧密联系的一个类,Looper类中维护了一个ThreadLocal对象,用于存放不同线程的Looper对象:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Looper对象的构造是通过Looper.prepare()方法实现的:
public static void prepare() {
// 默认情况下,quitAllowed为true,即looper对象可以退出循环并结束,但是在主线程中的looper不能退出循环,因为主线程所有的事件逻辑都在主线程的looper中进行轮询处理,如果退出loop循环,那么意味着主线程执行完了,应用结束。
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
// 每个线程的looper只可以创建一次
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
looper的执行只有一个方法,这个方法会进入一个死循环,在循环中不断获取消息队列中的消息然后分发给相应的handler进行处理:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
// 1 拿消息
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
try {
// 2 分发给handler处理
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
// 3 消息的回收
msg.recycleUnchecked();
}
}
Looper.loop在循环中主要做了三件事:
- 从消息队列MessageQueue中获取消息
- 将获取的消息给相应的handler进行处理
- 将处理完的消息进行回收
想看第一点,Message msg = queue.next(); // might block
源码的注释上写到:might block(有可能阻塞)。进入MessageQueue的next()方法:
Message next() {
// 这段与消息队列退出有关,可以对照quit()方法看
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 在native层阻塞
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 得到message,将message队列的对首给message.next,并返回message对象
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// 与Looper退出相关
if (mQuitting) {
dispose();
return null;
}
// 这里处理idle handlers.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[I];
mPendingIdleHandlers[i] = null;
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
// 如果idle handler 的queueIdle方法返回false那执行完就移除idleHandler队列
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
}
}
next()使用nativePollOnce(ptr, nextPollTimeoutMillis);
方法,在没有消息的时候进行阻塞,当有消息的时候再从mMessages中获取消息,然后判断是否到到执行消息的时间,如果到了就返回消息,否则就计算要等待的时间,然后下一次循环再调用nativePollOnce()
方法进行阻塞,直到消息需要执行了,然后返回消息。
nativePollOnce()
方法是一个native的方法:
/frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
long ptr
是java层线程创建Looper的时候创建MessageQueue时从native层获取的,对应的就是native 层的MessageQueue。android_os_MessageQueue_nativePollOnce方法会通过ptr先获取nativeMessageQueue对象,然后调用nativeMessageQueue的pollOnce方法:
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
//阻塞在这里 epoll_wait
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
最终调用mLooper->pollOnce(timeoutMillis);方法,当消息队列中没有消息,timeoutMillis(Java层的nextPollTimeoutMillis)= -1,就会阻塞。只有当新加入消息的时候会调用nativeWake(mPtr);
native方法:
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
void NativeMessageQueue::wake() {
// epoll_ctl
mLooper->wake();
}
最终调用mLooper->wake();
唤醒mLoop,此时nativePollOnce
方法往后执行,messageQueue.next()
才能获取message并返回。
至此,
- 从handler发送消息
- messageQueue将消息入队列
- looper轮询调用messageQueue的 next方法获取下一个需要处理的消息
- looper将消息分发给handler进行处理
整个流程完毕
总结
handler消息处理有一下几个大块:
- looper使用死循环轮询消息,使线程一直运行并监控发来的消息然后处理
- 在轮询的时候核心是通过messageQueue的next方法获取下一个要处理的消息,这里使用native层调用
epoll_wait
和epoll_clt
进行线程的阻塞和唤醒 - handler的obtain方法最终使用的是message的obtain方法,message类中维护类一个message池,为handler提供空白消息,池化的做法可以避免频繁创建对象,导致频繁GC