首页 文章 精选 留言 我的

精选列表

搜索[handler],共3636篇文章
优秀的个人博客,低调大师

Android应用程序消息处理机制(Looper、Handler)分析(3)

回到MessageQueue函数中,它接下来就是在进入等待状态前,看看有没有IdleHandler是需要执行的: //Iffirsttime,thengetthenumberofidlerstorun. if(pendingIdleHandlerCount<0){ pendingIdleHandlerCount=mIdleHandlers.size(); } if(pendingIdleHandlerCount==0){ //Noidlehandlerstorun.Loopandwaitsomemore. mBlocked=true; continue; } if(mPendingIdleHandlers==null){ mPendingIdleHandlers=newIdleHandler[Math.max(pendingIdleHandlerCount,4)]; } mPendingIdleHandlers=mIdleHandlers.toArray(mPendingIdleHandlers); 如果没有,即pendingIdleHandlerCount等于0,那下面的逻辑就不执行了,通过continue语句直接进入下一次循环,否则就要把注册在mIdleHandlers中的IdleHandler取出来,放在mPendingIdleHandlers数组中去。 接下来就是执行这些注册了的IdleHanlder了: //Runtheidlehandlers. //Weonlyeverreachthiscodeblockduringthefirstiteration. for(inti=0;i<pendingIdleHandlerCount;i++){ finalIdleHandleridler=mPendingIdleHandlers[i]; mPendingIdleHandlers[i]=null;//releasethereferencetothehandler booleankeep=false; try{ keep=idler.queueIdle(); }catch(Throwablet){ Log.wtf("MessageQueue","IdleHandlerthrewexception",t); } if(!keep){ synchronized(this){ mIdleHandlers.remove(idler); } } } 执行完这些IdleHandler之后,线程下次调用nativePollOnce函数时,就不设置超时时间了,因为,很有可能在执行IdleHandler的时候,已经有新的消息加入到消息队列中去了,因此,要重置nextPollTimeoutMillis的值: //Whilecallinganidlehandler,anewmessagecouldhavebeendelivered //sogobackandlookagainforapendingmessagewithoutwaiting. nextPollTimeoutMillis=0; 分析完MessageQueue的这个next函数之后,我们就要深入分析一下JNI方法nativePollOnce了,看看它是如何进入等待状态的,这个函数定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中: staticvoidandroid_os_MessageQueue_nativePollOnce(JNIEnv*env,jobjectobj, jintptr,jinttimeoutMillis){ NativeMessageQueue*nativeMessageQueue=reinterpret_cast<NativeMessageQueue*>(ptr); nativeMessageQueue->pollOnce(timeoutMillis); } 这个函数首先是通过传进入的参数ptr取回前面在Java层创建MessageQueue对象时在JNI层创建的NatvieMessageQueue对象,然后调用它的pollOnce函数: voidNativeMessageQueue::pollOnce(inttimeoutMillis){ mLooper->pollOnce(timeoutMillis); } 这里将操作转发给mLooper对象的pollOnce函数处理,这里的mLooper对象是在C++层的对象,它也是在前面在JNI层创建的NatvieMessageQueue对象时创建的,它的pollOnce函数定义在frameworks/base/libs/utils/Looper.cpp文件中: intLooper::pollOnce(inttimeoutMillis,int*outFd,int*outEvents,void**outData){ intresult=0; for(;;){ ...... if(result!=0){ ...... returnresult; } result=pollInner(timeoutMillis); } } 为了方便讨论,我们把这个函数的无关部分都去掉,它主要就是调用pollInner函数来进一步操作,如果pollInner返回值不等于0,这个函数就可以返回了。 函数pollInner的定义如下: intLooper::pollInner(inttimeoutMillis){ ...... intresult=ALOOPER_POLL_WAKE; ...... #ifdefLOOPER_USES_EPOLL structepoll_eventeventItems[EPOLL_MAX_EVENTS]; inteventCount=epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis); boolacquiredLock=false; #else ...... #endif if(eventCount<0){ if(errno==EINTR){ gotoDone; } LOGW("Pollfailedwithanunexpectederror,errno=%d",errno); result=ALOOPER_POLL_ERROR; gotoDone; } if(eventCount==0){ ...... result=ALOOPER_POLL_TIMEOUT; gotoDone; } ...... #ifdefLOOPER_USES_EPOLL for(inti=0;i<eventCount;i++){ intfd=eventItems[i].data.fd; uint32_tepollEvents=eventItems[i].events; if(fd==mWakeReadPipeFd){ if(epollEvents&EPOLLIN){ awoken(); }else{ LOGW("Ignoringunexpectedepollevents0x%xonwakereadpipe.",epollEvents); } }else{ ...... } } if(acquiredLock){ mLock.unlock(); } Done:; #else ...... #endif ...... returnresult; } 这里,首先是调用epoll_wait函数来看看epoll专用文件描述符mEpollFd所监控的文件描述符是否有IO事件发生,它设置监控的超时时间为timeoutMillis: inteventCount=epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis); 回忆一下前面的Looper的构造函数,我们在里面设置了要监控mWakeReadPipeFd文件描述符的EPOLLIN事件。 当mEpollFd所监控的文件描述符发生了要监控的IO事件后或者监控时间超时后,线程就从epoll_wait返回了,否则线程就会在epoll_wait函数中进入睡眠状态了。返回后如果eventCount等于0,就说明是超时了: if(eventCount==0){ ...... result=ALOOPER_POLL_TIMEOUT; gotoDone; } 如果eventCount不等于0,就说明发生要监控的事件: for(inti=0;i<eventCount;i++){ intfd=eventItems[i].data.fd; uint32_tepollEvents=eventItems[i].events; if(fd==mWakeReadPipeFd){ if(epollEvents&EPOLLIN){ awoken(); }else{ LOGW("Ignoringunexpectedepollevents0x%xonwakereadpipe.",epollEvents); } }else{ ...... } } 这里我们只关注mWakeReadPipeFd文件描述符上的事件,如果在mWakeReadPipeFd文件描述符上发生了EPOLLIN就说明应用程序中的消息队列里面有新的消息需要处理了,接下来它就会先调用awoken函数清空管道中把内容,以便下次再调用pollInner函数时,知道自从上次处理完消息队列中的消息后,有没有新的消息加进来。 函数awoken的实现很简单,它只是把管道中的内容都读取出来: voidLooper::awoken(){ ...... charbuffer[16]; ssize_tnRead; do{ nRead=read(mWakeReadPipeFd,buffer,sizeof(buffer)); }while((nRead==-1&&errno==EINTR)||nRead==sizeof(buffer)); } 因为当其它的线程向应用程序的消息队列加入新的消息时,会向这个管道写入新的内容来通知应用程序主线程有新的消息需要处理了,下面我们分析消息的发送的时候将会看到。 这样,消息的循环过程就分析完了,这部分逻辑还是比较复杂的,它利用Linux系统中的管道(pipe)进程间通信机制来实现消息的等待和处理,不过,了解了这部分内容之后,下面我们分析消息的发送和处理就简单多了。 本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966596,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册