Android事件分发原理

在Android中,Touch事件的分发分服务端和应用端。

服务端

服务端由WindowManagerService(借助InputManagerService)负责采集和分发的,在应用端则是由ViewRootImpl(内部有一个mView变量指向View树的根,负责控制View树的UI绘制和事件消息的分发)负责分发的。

image.png

当输入设备可用时,比如触屏,Linux内核会在/dev/input中创建对应的设备节点。
IMS(InputManagerService)监听/dev/input下的所有的设备节点,当设备节点有数据时会将数据进行加工处理并找到合适的Window(WMS寻找),将输入事件派发给他

  • 事件信号是物理文件存储数据,位置:dev/input
  • linux 有提供相关的文件监控api:inotify 、 epoll( ①inotify能监控文件变化产生FD ②epoll可以监控FD,以此配合完成文件的监控与监听)
  • android 定义了两个线程来处理dev/input下面的信号
  • 专门写了一个EventHub对象,里面用inotify+epoll对dev/input下进行监控!
  • 将该对象放到InputReaderThread当中去执行,轮训getEvent(),这个里面有epoll_wait,相当于wait-notify机制,唤醒的触发点是/dev/input下的文件被改变,这个文件由驱动去推送数据
  • InputReaderThread当中将/dev/input下的数据提取,封装,然后交给InputDispathcerThread
  • InputDispathcerThread给最终选择到对应的ViewRootImpl(Window)
  • 中间的通信机制通过socketpair进行,两边一人一组socketpair然后在ViewRootImpl中对于Channel的连接的文件进行监控,最终上层接受到touch信号。

client端

事件分发.PNG
  • 每一个Activity内部都包含一个Window用来管理要显示的视图。而Window是一个抽象类,其具体实现是 PhoneWindow类。
  • DecovrView作为PhoneWindow的一个内部类,实际管理着具体视图的显示。他是FrameLayout的子类,盛放着我们的标题栏和根视图。我们自己写的一些列View和ViewGroup都是由他来管理的。
  • 事件自顶向下的传递过程应该是这样的:
    Activity(不处理)-> 根View -> 一层一层ViewGroup(如果有的话) -> 子View
  • 如果传递到最后我们的子View们没有处理这一事件怎么办呢?这时候就会原路返回,最终传递给Activity。只有当Activity也没有处理这一事件时,这一事件才会被丢弃。
    Activity(不处理则丢弃) <- 根View <- 一层一层ViewGroup(如果有的话) <- 子View

具体在传递事件的时候,是由以下三个方法来控制的:

dispatchTouchEvent : 分发事件
onInterceptTouchEvent : 拦截事件
onTouchEvent : 消费事件
这三个方法有一个共同点,就是他们具体是否执行了自己的功能(分发、拦截、消费)完全由自己的返回值来确定,返回true就表示自己完成了自己的功能(分发、拦截、消费)。不同之处除了功能外,还有使用的场景。dispatchTouchEvent()和onTouchEvent()这两个方法,无论是Activity ViewGroup 还是View,都会被用到。而onInterceptTouchEvent()方法因为只是为了拦截事件,那么Activity和View一个在最顶层,一个在最底层,也就没必要使用了。因此在View 和 Activity中是没有onInterceptTouchEvent()方法的。

参考链接:https://blog.csdn.net/qq_42165012/article/details/123163462

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容