Android應用程序消息處理機制(Looper、Handler)分析(9)
這里,首先是調(diào)用epoll_wait函數(shù)來看看epoll專用文件描述符mEpollFd所監(jiān)控的文件描述符是否有IO事件發(fā)生,它設置監(jiān)控的超時時間為timeoutMillis:
- [cpp] view plaincopyint eventCount = epoll_wait(mEpollFd, eventItems,
- EPOLL_MAX_EVENTS, timeoutMillis);
回憶一下前面的Looper的構(gòu)造函數(shù),我們在里面設置了要監(jiān)控mWakeReadPipeFd文件描述符的EPOLLIN事件。
當mEpollFd所監(jiān)控的文件描述符發(fā)生了要監(jiān)控的IO事件后或者監(jiān)控時間超時后,線程就從epoll_wait返回了,否則線程就會在epoll_wait函數(shù)中進入睡眠狀態(tài)了。
返回后如果eventCount等于0,就說明是超時了:
- [cpp] view plaincopyif (eventCount == 0) {
- ......
- result = ALOOPER_POLL_TIMEOUT;
- goto Done;
- }
如果eventCount不等于0,就說明發(fā)生要監(jiān)控的事件:
- [cpp] view plaincopyfor (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();
- } else {
- LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.",
- epollEvents);
- }
- } else {
- ......
- }
- }
這里我們只關注mWakeReadPipeFd文件描述符上的事件,如果在mWakeReadPipeFd文件描述符上發(fā)生了EPOLLIN就說明應用程 序中的消息隊列里面有新的消息需要處理了,接下來它就會先調(diào)用awoken函數(shù)清空管道中把內(nèi)容,以便下次再調(diào)用pollInner函數(shù)時,知道自從上次 處理完消息隊列中的消息后,有沒有新的消息加進來。
函數(shù)awoken的實現(xiàn)很簡單,它只是把管道中的內(nèi)容都讀取出來:
- [cpp] view plaincopyvoid Looper::awoken() {
- ......
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead ==
- zeof(buffer));
- }
因為當其它的線程向應用程序的消息隊列加入新的消息時,會向這個管道寫入新的內(nèi)容來通知應用程序主線程有新的消息需要處理了,下面我們分析消息的發(fā)送的時候?qū)吹健?/p>
這樣,消息的循環(huán)過程就分析完了,這部分邏輯還是比較復雜的,它利用Linux系統(tǒng)中的管道(pipe)進程間通信機制來實現(xiàn)消息的等待和處理,不過,了解了這部分內(nèi)容之后,下面我們分析消息的發(fā)送和處理就簡單多了。