1.初始化MainLooper,保存在静态变量ThreadLocal里面
ActivityThread.java
Looper.prepareMainLooper();
prepare();
sThreadLocal.set(new Looper());
mQueue = new MessageQueue();
setMainLooper(myLooper());
myLooper() = (Looper)sThreadLocal.get();
2.开启无限循环。
Looper.loop();
3.MessageQueue初始化
MessageQueue();
nativeInit();
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
new Looper(); // 创建JNI层Looper;
setNativeMessageQueue();
// 通过反射把Java层的MessageQueue里面的mPtr变量设置成JNI层的
// NativeMessageQueue的指针.方便调用时找到是哪个
env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
reinterpret_cast<jint>(nativeMessageQueue));
4. JNI层Looper初始化
简单来说,管道就是一个文件,在管道的两端,分别是两个打开文件文件描述符,这两个打开文件描述符都是对应同一个文件,
其中一个是用来读的,别一个是用来写的,一般的使用方式就是,一个线程通过读文件描述符中来读管道的内容,当管道没有内容时,
这个线程就会进入等待状态,而另外一个线程通过写文件描述符来向管道中写入内容,写入内容的时候,
如果另一端正有线程正在等待管道中的内容,那么这个线程就会被唤醒。
Looper::Looper(bool allowNonCallbacks);
int wakeFds[2];
int result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// EPOLL_SIZE_HINT 能监控的最大描述符数量
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
......
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
// 监控管道的读端
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
5. 这里只做了两件事,取消息和分发消息
Looper.loop();
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
6. 取消息
MessageQueue.next();
nativePollOnce(mPtr, nextPollTimeoutMillis); // nextPollTimeoutMillis 取值有 0 n>0 -1 0: 不等待 n>0: 等待n毫秒后自动唤醒; -1: 无限等待
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); // 通过mPtr找到对应的JNI层的MQ
nativeMessageQueue->pollOnce(timeoutMillis);
mLooper->pollOnce(timeoutMillis);
result = pollInner(timeoutMillis);
// 等待在这个位置 eventCount > 0 说明会有监控事件
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken(); // 把管道的内容读取出来
}
}
}
7. 发消息 以及唤醒第六步阻塞的位置 唤醒后,走第五步分发流程
mq.enqueueMessage(msg, uptimeMillis);
nativeWake(mPtr);
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
return nativeMessageQueue->wake();
ssize_t nWrite;
do {
nWrite = write(mWakeWritePipeFd, "W", 1);
} while (nWrite == -1 && errno == EINTR);
Android Handler机制笔记
最新推荐文章于 2024-05-02 19:15:42 发布
本文深入解析了Android消息机制,包括Looper的初始化、无限循环处理、MessageQueue的创建、JNI层的管道实现以及消息的发送与接收流程。详细阐述了如何通过管道和Epoll实现线程间的通信,确保消息的高效分发。
摘要由CSDN通过智能技术生成