MessageQueue 是一个消息队列,可放可取
1.先看其构造函数,不是共有的,开发者不能创建这个对象,必须有系统去创建和初始化;在构造函数中调用了一个nativeInit方法;
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
nativeInit();
}
2.nativeInit方法的实现什么东西?对应底层的C++函数如下,在android_os_MessageQueue.cpp中:
static voidandroid_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
// NativeMessageQueue是MessageQueue在Native层的代表
NativeMessageQueue* nativeMessageQueue = newNativeMessageQueue();
......
// 将这个NativeMessageQueue对象设置到Java层保存
android_os_MessageQueue_setNativeMessageQueue(env,obj,nativeMessageQueue);
}
从上面代码可以看出,这个MessageQueue队列是在底层创建的;
3.我们在看看NativeMessageQueue对象的构造函数:
NativeMessageQueue::NativeMessageQueue() {
/* 代表消息循环的Looper也在Native层中呈现身影了。根据消息驱动的知识,一个线程会有一个
Looper来循环处理消息队列中的消息。下面一行的调用就是取得保存在线程本地存储空间
(Thread Local Storage)中的Looper对象 */
mLooper= Looper::getForThread();
if (mLooper == NULL) {
/* 如为第一次进来,则该线程没有设置本地存储,所以须先创建一个Looper,然后再将其保存到
TLS中,这是很常见的一种以线程为单位的单例模式*/
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
这里出现了一个Looper,但是这个和java层的Looper是两个不同的概念;是native层参与消息轮询的参与者;
4.那么是如何发送消息的呢?在MessageQueue中有的enqueueMessage方法;
final boolean enqueueMessage(Message msg, longwhen) {
......
finalboolean needWake;
synchronized (this) {
if(mQuiting) {
return false;
}else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
Message p = mMessages;
if(p == null || when == 0 || when < p.when) {
/* 如果p为空,表明消息队列中没有消息,那么msg将是第一个消息,needWake
需要根据mBlocked的情况考虑是否触发 */
msg.next= p;
mMessages = msg;
needWake = mBlocked;
} else {
// 如果p不为空,表明消息队列中还有剩余消息,需要将新的msg加到消息尾
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
// 因为消息队列之前还剩余有消息,所以这里不用调用nativeWakeup
needWake = false;
}
}
if(needWake) {
// 调用nativeWake,以触发nativePollOnce函数结束等待
nativeWake(mPtr);
}
returntrue;
}
将消息按照时间的顺序插入到消息队列中,然后去唤醒主线程调用nativeWake唤醒;代码如下:
static voidandroid_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr){
NativeMessageQueue* nativeMessageQueue = // 取出NativeMessageQueue对象
reinterpret_cast<NativeMessageQueue*>(ptr);
returnnativeMessageQueue->wake(); // 调用它的wake函数
}
void NativeMessageQueue::wake() {
mLooper->wake(); // 层层调用,现在转到mLooper的wake函数
}
//Native Looper的wake函数代码如下:
void Looper::wake() {
ssize_tnWrite;
do {
// 向管道的写端写入一个字符
nWrite = write(mWakeWritePipeFd, "W", 1);
} while(nWrite == -1 && errno == EINTR);
}
可以看到唤醒的方法是在管道中写了一个字符“w”;这样MessageQueue中的next方法就可以调用底层的nativePollOnce就可以读到唤醒消息,唤醒主线程;5.当java层在ActivityThread中的main方法中调用了Looper.loop()后,主线程就进入一个while(true)循环中,循环调用Messagequeue的next()方法;下面就看看next中做了什么?是如何阻塞主线程的?
final Message next() {
int pendingIdleHandlerCount = -1;
int nextPollTimeoutMillis = 0;
for (;;) {
......
// mPtr保存了NativeMessageQueue的指针,调用nativePollOnce进行等待
nativePollOnce(mPtr,nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
// mMessages用来存储消息,这里从其中取一个消息进行处理
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {
mBlocked = false;
mMessages = msg.next;
msg.next = null;
msg.markInUse();
return msg; // 返回一个Message给Looper进行派发和处理
} else {
nextPollTimeoutMillis = (int) Math.min(when- now,Integer.MAX_VALUE);
}
} else {
nextPollTimeoutMillis = -1;
}
......
/* 处理注册的IdleHandler,当MessageQueue中没有Message时,
Looper会调用IdleHandler做一些工作,例如做垃圾回收等 */
......
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
}
在上面的代码中,又是一个死循环,定义了一个long类型的mPtr变量传入底层;在看看nativiePollOnce这个函数,函数会阻塞,读取管道中的唤醒主线程的信息,读不到会阻塞;
static voidandroid_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jintptr, jint timeoutMillis)
NativeMessageQueue* nativeMessageQueue =
reinterpret_cast<NativeMessageQueue*>(ptr);
// 取出NativeMessageQueue对象,并调用它的pollOnce
nativeMessageQueue->pollOnce(timeoutMillis);
}
void NativeMessageQueue::pollOnce(inttimeoutMillis) {
mLooper->pollOnce(timeoutMillis); // 重任传递到Looper的pollOnce函数
}
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
发现调用进去后,是层层调用,最后调用了native层的轮询器mLooper的pollOnce函数;最终是在这个函数中实现阻塞式读取管道的唤醒信息;
MessageQueue中实现了消息的发送,轮询接受,移除,还是实现了利用liunx的通道机制实现线程的唤醒,这部分代码是在底层实现的;