之前在子线程和主线程创建使用Handler不同处的源码分析时,追了一下应用创建和使用Handler的相关源码。发现了在线程中使用Handler,最后就会进入loop循环,子线程要手动退出,主线程是不死就不退出;同时也和另一个问题相遇了:那就是应用的主线程最后也都在loop里没出来【activityThread的Main方法最后执行了Looper.loop()】为什么不会导致应用发生ANR呢?.今天不对这具体深入;就主要对Handler的消息循环,消息发送和消息处理的流程进行分析.这块梳理完后,对不引发ANR的问题也就可以帮助理解了
在loop循环中,会一直等待和处理消息。我们就从Looper.java的loop()方法入手:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
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 (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
....
msg.recycleUnchecked();
}
}
在loop()中,先对其中的重要的变量进行说明:
me : looper对象,在Looper.java类的prepare()方法中创建,并保存在sMainLooper中,这里通过myLooper()方法获取到
queue:MessageQueue对象,在Looper类构造函数里创建的,所以Looper中就持有了messageQueue的对象。
msg: Message;
msg.target:这就是handler
loop中有个for大循环,里面就在不断的获取和处理消息。在循环中,先使用MessageQueue的next()方法从MessageQueue中获取message,如果返回的消息为空,loop就会退出-->线程就会退出(要是在主线程中的话-->最后应用也会退出)。我这看到这里时就很疑惑了,难道一个应用在活着的时候,他的MessageQueue就不能为空?但是显然应用的MessageQueue是为有空的时候,那问题应该就出在messageQueue的next()方法里,或许这个next()里面有什么特殊,导致不会返回空。
抱着问题跳转到MessageQueue.java中看看这个next()方法里面是怎么样做的:
Message next() {
final long ptr = mPtr;
...
int nextPollTimeoutMillis = 0;
for (;;) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);
...
}
}
在nex()方法中也有个for循环,它里面有个nativePollOnce()调用。我们就看看Native层的实现,接下来跳转到Native层的android_os_MessageQueue.cpp【这是MessageQueue对应的Native文件】
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
在android_os_MessageQueue_nativePollOnc()函数里面,通过nativePollOnce传进来的ptr找到NativeMessageQueue指针。然后调用其pollOnce()函数:
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
...
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
...
}
在pollOnce()函数中这个mLooper就是Looper的一个指针,在android_os_MessageQueue.h中声明的,所以在Native层的MessageQueue持有Looper指针,【Java层是Looper中持有MessageQueue对象】接着是调用了Looper的pollOnce()方法:
我们就跳转到Looper.cpp中看看Looper的pollOnce()是怎么做的:
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
...
result = pollInner(timeoutMillis);
}
}
在pollOnce()中的for循环中调用了pollInner();我们在跳转到pollInner()中看看:
int Looper::pollInner(int timeoutMillis) {
...
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
...
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
result = POLL_ERROR;
goto Done;
}
if (eventCount == 0) {
...
result = POLL_TIMEOUT;
goto Done;
}
...
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd) {
if (epollEvents & EPOLLIN) {
awoken();
...
}
...
return result;
}
在pollInner()中,使用epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);来检测mEpollFd所监控的fd是否有IO事件发生,超时时间为timeoutMillis[这也是随我们从Java层传下来的]:【关于epoll,我们在之前分析Android_input系统分析EventHub::getevents时也有涉及,具体使用可以参考参考】
当mEpollFd所监控的文件描述符发生了要监控的IO事件后或者监控时间超时后,线程就从epoll_wait返回了,否则线程就会在epoll_wait函数中进入睡眠状态了。返回后如果eventCount等于0,说明等待超时。果eventCount小于0,说明有错误。当eventCount大于0时,说明有IO事件发生:接着我们看awoken():
void Looper::awoken() {
uint64_t counter;
TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}
awoken()就是将mWakeEventFd句柄中的数据读出。他的作用就是把mWakeEventFd里面原有的数据读走,以便下次再写入。
到这里,差不多就把消息循环大致流程梳理完了。我们可以发现,当MessageQueue为空时,也不会返回为空,而是线程进入休眠状态,在native层使用epoll来监听是否有新的消息从而唤醒线程进行消息获取,所以在没有手动退出和没错误发生的情况下loop()是一直没有退出,从而线程,进程都不会退出。
消息的发送不论我们使用Handler的sendMessageXXX()还是post()方法,最后都调用了sendMessageDelayed()方法;我们接下来就从Handler.java 的sendMessageDelaye()方法出发看看消息发送的流程是怎么样的:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
在sendMessageDelaye()方法中右调用了sendMessageAtTime()方法,我们接着跳转到sendMessageAtTime()方法中看看:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
...
return enqueueMessage(queue, msg, uptimeMillis);
}
...
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
从以上代码可以看出,最后在Handler中调用了MessageQueue中的enqueueMessage()方法:
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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 {
...
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;
}
以上就是MessageQueue.java的enqueueMessage()方法,主要工作就是
消息插入到MessageQueue中时有两种情况:
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
}
①. 当时消息队列此时消息为空,如上代码所示:直接将我们的消息放进去就好,说明此时messageQueue是阻塞状态的,我们需要唤醒事件队列;
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;
②.如果当前消息队列不为空,那我们就要把我们要发送的消息插入带消息队列中去,这需要根据消息的时间来决定的我们插入到消息队列中的位置,具体逻辑参看上梳代码。
当消息队列为空此时线程就需要我们去唤醒,这里是使用了一个Native方法nativeWake:那我们就跳转到Native层看看是怎么唤醒线程的,接下来我们跳转到android_os_MessageQueue.cpp中查看一下:
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
nativeMessageQueue->wake();
}
...
void NativeMessageQueue::wake() {
mLooper->wake();
}
...
void Looper::wake() {
...
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
...
}
如上所以:这和消息循环是调用差不多,在Native层的android_os_MessageQueue中,最终是调用了Looper的wake(),在wake()中向mWakeEventFd写入数据,这个数据具体是什么不重要,主要当有数据写入;另一边的epoll_wait()就可以检测到有新的IO事件发生,从而唤醒线程来获取和处理消息。
那接下来,消息队列理里有消息了,我们就需要几及时去处理消息;我们继续回到Looper.java中的loop()方法中,看到有下面这段代码:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
在for循环中不断地获取消息队列中的消息,【之前说过,当没有消息时,线程就会阻塞,所以这里的msg正常情况是不为空的】
这里是调用msg.target 的dispatchMessage()方法去处理消息;【之前说过,msg.target其实就是handler】.接下里我们看看Handler.java中是怎么处理的:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
...
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
如上所示:如果msg 的callback不为空,就执行handleCallback()方法,否则如果mCallback不为空,就执行mCallbackd的handleMessage()方法;否则执行handleMessage()方法,一般情况是默认执行handleMessage()方法来处理消息.所以Handler 的子类必须要实现ahndleMessage()方法。对接收到的消息进行处理。