转眼间近一年没更新博客了,工作一忙起来,很难有时间来写博客了,由于现在也在从事Android开发相关的工作,因此以后的博文也会更多地专注于这一块。
这篇文章准备从源码层面为大家带来Touch事件的传递机制,我这里分析的源码时Android4.4的。说到分析源码,光看肯定是不行的,一定要亲自去跟,并且要边跟边思考,所以在下一篇中,会有一个Demo来为大家详细分析源码的走向。
下面进入正题,先来看下Android中事件的分类:
1、键盘事件:主要是指按下虚拟键盘的某个按键、或者机身的物理按键时产生的事件。
2、鼠标事件:Android4.0之后增加了对鼠标事件的监控,如ACTION_HOVER_ENTER。
3、触摸屏事件:凡是触摸屏幕而产生的事件都是触摸屏事件,触摸屏事件包括很多,比如单点触控、多点触控)、轨迹球事件等。
我们这里主要讲解单点触控事件,也就是Touch事件的传递,首先看下Touch事件的完整传递过程:
1、首先需要明白,Android中,Touch事件的分发分服务端和应用端。在Server端由WindowManagerService(WMS,窗口管理服务,不懂的自行脑补)负责采集和分发的,在client端则是由ViewRootImpl(内部有个mView变量指向View树的根 ,负责控制View树的UI绘制和事件消息的分发)负责分发的。
2、WMS在启动之后,经过逐层调用,会在native层启动两个线程:InputReaderThread和InputDispatchThread,前者用来读取输入事件,
后者用来分发输入事件,输入事件经过nativie层的层层传递,最终会传递到java层的ViewRootImpl中,调用
ViewPostImeInputStage(ViewRootImpl的内部类)中的各个方法来分发不同的事件,而Touch事件是在processPointerEvent方法进行分发的(这部分代码很单,可自行查看)。
3、processPointerEvent方法中调用mView.dispatchPointerEvent(event)方法,这里的mView就是在创建窗口后通过调用root.setView传进
来的DecorView,而dispatchPointerEvent方法会对event进行判断,如果是Touch事件的话,就调用dispatchTouchEvent将该事件分发DecorView,这样,Touch事件就传递到了View树中了。
Touch事件从WMS到ViewRootImpl的传递
下面这张图(不是自己画的,网上找的,Android4.4中,InputManager变成了InputManagerService,ViewRoot变成了ViewRootImpl)展示了Touch事件
从WMS(sever端)传递到ViewRootImpl(client端)的流程。
这里需要特别注意的是,Touch事件从server端传递到client端采用的IPC方式并不是Binder,而是共享内存和管道,至于为什么不采用Binder,应该是共享内存的效率更高,而管道(注意,两个管道,分别负责不同方向的读和写)只负责通知是否有事件发生,传递的只是一个很简单的字符串,因此并不会太多地影响到IPC的效率。
上图中,只有WMS、ViewRootImpl、InputManagerService、InputQueue是在FrameWork层实现的,其他部分都是在native层实现的,native 层的代码没有细看,参考了些网上的一些资料和公司内部的一些分享,把整个流程串通了,这部分代码,如果时间充足,可以深入研究下。
在sever端中,InputReader和InputDispatcher是native 层的两个线程,前者不断地从EventHub中读取事件(包括所有的事件,对不同的事件会做判断处