关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android应用程序消息处理机制

    Android应用程序消息处理机制

    2015-07-14 00:00:00 出处:IT_xiao小巫
    分享

    Android的消息处理机制主要分为四个部分:

    创建消息队列 消息循环 消息发送 消息处理

    主要涉及三个类:

    MessageQueue Looper Handler

    Android应用程序每启动一个线程,都为其创建一个消息队列,然后进入到一个无限循环之中。然后不断检查队列中是否有新消息需要处理。假如没有,线程就会进入睡眠状态,反之会对消息进行分发处理。

    下面根据上面所说的进行详述。

    创建消息队列

    整个创建过程涉及到两个类:MessageQueue 和 Looper。它们在C++层有两个对应的类:NativeMessageQueue和Looper。其关系如下图所示:

              +------+    +------------+  +------------------+  +--------------+                    
              |Looper|    |MessageQueue|  |NativeMessageQueue|  |Looper(Native)|                    
              +--+---+    +------+-----+  +---------+--------+  +-------+------+                    
                 |               |                  |                   |                           
                 |               |                  |                   |                           
    +-------------------------------------------------------------------------------+               
    |[msg loop]  |   next()      |                  |                   |           |               
    |            +------------>  |                  |                   |           |               
    |            |               |                  |                   |           |               
    |            |               |                  |                   |           |               
    |            |               | nativePollOnce() |                   |           |               
    |            |               |    pollOnce()    |                   |           |               
    |            |               +----------------> |                   |           |               
    |            |               |                  |                   |           |              
    |            |               |                  |                   |           |               
    |            |               |                  |                   |           |               
    |            |               |                  |                   |           |               
    |            |               |                  |     pollOnce()    |           |               
    |            |               |                  +-----------------> |           |               
    |            |               |                  |                   |           |               
    |            |               |                  |                   | epoll_wait()              
    |            |               |                  |                   +--------+  |               
    |            |               |                  |                   |        |  |               
    |            |               |                  |                   |        |  |               
    |            |               |                  |                   | <------+  |               
    |            |               |                  |                   | awoken()  |               
    |            +               +                  +                   +           |               
    |                                                                               |               
    |                                                                               |               
    +-------------------------------------------------------------------------------+

    创建过程如下所示:

    Looper的prepare或者prepareMainLooper静态方法被调用,将一个Looper对象保存在ThreadLocal里面。 Looper对象的初始化方法里,首先会新建一个MessageQueue对象。 MessageQueue对象的初始化方法通过JNI初始化C++层的NativeMessageQueue对象。 NativeMessageQueue对象在创建过程中,会初始化一个C++层的Looper对象。 C++层的Looper对象在创建的过程中,会在内部创建一个管道(pipe),并将这个管道的读写fd都保存在mWakeReadPipeFd和mWakeWritePipeFd中。
    然后新建一个epoll实例,并将两个fd注册进去。 利用epoll的机制,可以做到当管道没有消息时,线程睡眠在读端的fd上,当其他线程往管道写数据时,本线程便会被唤醒以进行消息处理。

    消息循环

             +-------+     +------------+   +------------------+   +--------------+                        
              |Handler|     |MessageQueue|   |NativeMessageQueue|   |Looper(Native)|                        
              +--+----+     +-----+------+   +---------+--------+   +-------+------+                        
                 |                |                    |                    |                               
                 |                |                    |                    |                               
    sendMessage()|                |                    |                    |                               
    +----------> |                |                    |                    |                               
                 |                |                    |                    |                               
                 |enqueueMessage()|                    |                    |                               
                 +--------------> |                    |                    |                               
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 |                |  nativeWake()      |                    |                               
                 |                |    wake()          |                    |                               
                 |                +------------------> |                    |                               
                 |                |                    |                    |                               
                 |                |                    |    wake()          |                               
                 |                |                    +------------------> |                               
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 |                |                    |                    |write(mWakeWritePipeFd, "W", 1)
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 |                |                    |                    |                               
                 +                +                    +                    +

    首先通过调用Looper的loop方法开始消息监听。loop方法里会调用MessageQueue的next方法。next方法会堵塞线程直到有消息到来为止。

    next方法通过调用nativePollOnce方法来监听事件。next方法内部逻辑如下所示(简化):

    a. 进入死循环,以参数timout=0调用nativePollOnce方法。 b. 假如消息队列中有消息,nativePollOnce方法会将消息保存在mMessage成员中。nativePollOnce方法返回后立刻检查mMessage成员是否为空。 c. 假如mMessage不为空,那么检查它指定的运行时间。假如比当前时间要前,那么马上返回这个mMessage,否则设置timeout为两者之差,进入下一次循环。 d. 假如mMessage为空,那么设置timeout为-1,即下次循环nativePollOnce永久堵塞。

    nativePollOnce方法内部利用epoll机制在之前建立的管道上等待数据写入。接收到数据后马上读取并返回结果。

    消息发送

                +------+       +-------+                                                                   
                 |Looper|       |Handler|                                                                   
                 +--+---+       +---+---+                                                                   
                    |               |                                                                       
                    |               |                                                                       
        loop()      |               |                                                                       
        [after next()]              |                                                                       
        +---------> |               |                                                                       
                    |               |                                                                       
                    |dispatchMessage()                                                                      
                    +-------------> |                                                                       
                    |               |                                                                       
                    |               |                                                                       
                    |               | handleMessage()                                                       
                    |               +-------+                                                               
                    |               |       |                                                               
                    |               |       |                                                               
                    |               | <-----+                                                               
                    |               |   (callback or subclass)                                              
                    |               |                                                                       
                    +               +

    消息发送过程主要由Handler对象来驱动。

    Handler对象在创建时会保存当前线程的looper和MessageQueue,假如传入Callback的话也会保存起来。 用户调用handler对象的sendMessage方法,传入msg对象。handler通过调用MessageQueue的enqueueMessage方法将消息压入MessageQueue。 enqueueMessage方法会将传入的消息对象根据触发时间(when)插入到message queue中。然后判断是否要唤醒等待中的队列。
    a. 假如插在队列中间。说明该消息不需要马上处理,不需要由这个消息来唤醒队列。
    b. 假如插在队列头部(或者when=0),则表明要马上处理这个消息。假如当前队列正在堵塞,则需要唤醒它进行处理。 假如需要唤醒队列,则通过nativeWake方法,往前面提到的管道中写入一个”W”字符,令nativePollOnce方法返回。

    消息处理

    +------+ +-------+  |Looper|       |Handler| +--+---+ +---+---+  | | | | loop() | | [after next()] | +---------> | |  | | |dispatchMessage() +-------------> |  | | | | | | handleMessage() | +-------+  | | | | | | | | <-----+  | | (callback or subclass) | | + + 

    Looper对象的loop方法里面的queue.next方法假如返回了message,那么handler的dispatchMessage会被调用。

    a. 假如新建Handler的时候传入了callback实例,那么callback的handleMessage方法会被调用。
    b. 假如是通过post方法向handler传入runnable对象的,那么runnable对象的run方法会被调用。
    c. 其他情况下,handler方法的handleMessage会被调用。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    IT头条

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    严重缩水!NVIDIA将推中国特供RTX 5090 DD:只剩24GB显存

    00:17

    无线路由大厂 TP-Link突然大裁员:补偿N+3

    02:39

    Meta 千万美金招募AI高级人才

    00:22

    技术热点

    Spring基础知识汇总 Java开发必看

    SQL Server索引与其性能的描述

    SQL Server 2008数据格式修改时应注意什么?

    如何禁止windows 7网络搜索驱动?windows 7禁止网络搜索驱动的方

    SQL Server系统表中的sysconfigures表

    如何恢复windows 7、windows 8图片预览功能详细图解

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。