前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android源码分析之鼠标事件监听(二)

Android源码分析之鼠标事件监听(二)

作者头像
fanfan
发布2019-07-10 16:07:16
1.5K0
发布2019-07-10 16:07:16
举报
文章被收录于专栏:编程思想之路编程思想之路

本文是一篇很长~很长~很长~~~的技术笔记 如果有什么问题,欢迎指正.

Zero 前言

前边儿已经说过,要想了解鼠标就要研究三个东西

  • 鼠标的挂载/卸载
  • 鼠标事件处理,也就是鼠标操作
  • 鼠标绘制

不论是鼠标挂载/卸载还是鼠标操作,基本上算是对输入事件的一个监听了,属于一类东西 但是鼠标绘制,这涉及到surface绘制鼠标,对于我本人,基本上没接触过那么多绘制的东西,一点点尝试分析. 鼠标事件本身又包括什么?

  • 事件监听
  • 事件处理

接下来实现一个阶段性的小目标,就先愉快的分析一下鼠标事件的监听吧. ok,怎么分析? 从宏观角度出发,千万别一头扎进某个小片段里. 先整体看下整个流程,再来特殊分析. 鼠标也属于输入设备对吧,那鼠标是不是遵循针对输入设备的处理逻辑? 你总不至于给每一种输入设备都配置一套独特的逻辑吧?那岂不是太冗余了. 逻辑是一套,只不过在处理时需要区分一下type而已. 所以呢,本文就来分析手机是如何监听输入事件InputEvent的?

One IMS

这个有时候也需要一些基础和经验. 源码中管理输入的服务是什么?IMS(InputManagerService) 那就从InputManager.h(目录位于/frameworks/native/services/inputflinger/)出发 为啥我先看头文件? 第一,头文件一般会有注释说明,交代整个文件作用,便于代码理解 第二,头文件可以直接看出代码结构structure.一眼就可以知道有哪些方法,哪些filed 果然没让我失望,这个文件里的注释完全表明了framework层所做的工作. 原文就不贴了,有想看的可以在线查看源码,传送门-->http://androidxref.com/9.0.0_r3/xref/frameworks/native/services/inputflinger/InputManager.h 意思是什么,IM是系统核心进程(这不是废话吗?要不然怎么输入). 接下来关键了 说IM管理着两个进程InputReaderThread和InputDispatcherThread,也终于找到了管理输入的重点 顾名思义,一个负责(read)读取inputEvent,一个负责(dispatch)分发inputEvent,各司其职 读取时的事件成为原始输入事件,叫做rawEvent.分发出去的是处理之后的输入事件inputEvent. 那为什么要分两个线程呢?

TWO 饭来了

其实很好理解,就像是饭店门口总有迎宾带路的,坐下之后又会有点餐员一个道理.两个角色都需要等待,也就是都会有阻塞. 迎宾的服务员相当于是在一直监听有哪些顾客进来,并把这些顾客带到对应位置,对于迎宾员而言,只知道顾客是来吃饭的,不知道具体吃什么. 点餐员相当于需要去记录对应顾客的菜单menu,并且分发给对应厨师来进行处理. 那么饭店相当于什么呢?饭店是不是相当于一个储存消息的队列?迎宾员把顾客放到这个队列,之后点餐员开始和队列中的顾客接洽,并生成顾客的菜单传递给厨师. 那为什么要分两个人处理呢?如果一个人会是什么情况? 比如来了一波儿顾客,服务员需要把他领导座位,并且下单结束,之后再把单交给厨师.如果在这个过程中又来了一波儿人,那就只能等待…. 随便问一句,现在谁有那么多耐心去等啊.更别说电子设备这种需要及时响应的了. 从这儿看,生活真是无处不符合逻辑知识啊~ 输入事件的处理也是这个逻辑.流程也就出来了 InputReaderThread需要在系统准备好就要开启监听输入事件的到来,相当于饭店营业开始时,迎宾人员开始等候 在InputReaderThread监听到输入事件时,就要把原始事件rawEvent插入到队列中,相当于一层透传,也就相当于迎宾人员将顾客带到座位 至此,InputReaderThread的任务就完成了,接下来就该点餐员上场了 InputDispatcherThread要干什么?要循环从队列中取数据,也就是要去观察是否有新的顾客落座,并开始下单. 下单的过程也是相当于一个处理的过程,完成了原始事件到系统特定输入事件的转换rawEvent--->inputEvent. 紧接着就是把菜单交给厨师,任务over 到这儿dispatcher的任务也完成了,接下来就是需要厨师根据菜单做菜了.这就相当于不同应用对应不同输入事件的处理. 比如在应用中监听按钮点击事件,当点击按钮时会触发该事件. 在这个过程中,有一个逻辑,点餐员在下完单之后需要告诉迎宾员吗?不需要的,所以呀,这个事件的处理是单向的. 分两个线程处理可以实现快速响应输入事件. reader线程监听到事件后直接插入到队列中,就可以继续监听,来保证缩短用户输入开始到接收到输入事件的时间 dispatcher线程会一直取出新的输入事件,重点是异步分发给对应应用处理.缩短分发时间. 好了,为了方便理解和记忆,以上都是口语化的解释,接下来该官方描述一下了

Three 源码

  • InputReaderThread:用于读取和预处理原始输入事件,并且把事件插入到由dispatcherThread管理的队列中.在输入事件来临前一直阻塞
  • InputDispatcherThread:等待队列中有新的输入事件(来临前阻塞),并且异步分发给对应的应用

理论结束,接下来大致看一下代码:

InputManager

InputManager.h中超级简单,四个filed,五个方法(排除掉构造方法)

代码语言:javascript
复制
 1public:
 2    virtual status_t start();//开启两个线程(执行run方法)
 3   virtual status_t stop();//退出两个线程(requestExitAndWait)
 4
 5    virtual sp<InputReaderInterface> getReader();
 6    virtual sp<InputDispatcherInterface> getDispatcher();
 7
 8private:
 9    sp<InputReaderInterface> mReader;
10    sp<InputReaderThread> mReaderThread;//readerThread实例
11
12    sp<InputDispatcherInterface> mDispatcher;
13    sp<InputDispatcherThread> mDispatcherThread;//dispatcherThread实例
14
15    void initialize();//用于初始化两个thread对象
16};

方法实现也很简单,不再贴出.接下来看下两个线程做了什么?

InputReader

InputReaderThread在InputReader文件中.目录为: /frameworks/native/services/inputflinger/InputReader.cpp 传送门---> http://androidxref.com/9.0.0_r3/xref/frameworks/native/services/inputflinger/InputReader.cpp 在线程run之后,会触发threadLoop方法,来看看InputReaderThread的线程做了什么?

代码语言:javascript
复制
1bool InputReaderThread::threadLoop() {
2    mReader->loopOnce();
3    return true;
4}

就是这么easy,触发了InputReader的loopOnce.一级级的追吧

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Zero 前言
  • One IMS
  • TWO 饭来了
  • Three 源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档