不多说,进入正题:

关于Android中的Touch事件分发, 分为 服务端WindowManagerService(WmS,以下都以WmS简称), 负责采集与分发. 经过一些列调用, 会分发到client端 viewrootimpl中, 然后viewrootimpl进行client端的touch事件分发

首先我们要知道的是,在WmS启动后,经过逐层调用,会在native层启动InputReaderThread,InputDispatchThread,这两个线程负责touch事件的采集和分发,前者用来读取输入事件,后者则用来分发事件. 经过native的层层调用,最后会传递到ViewRootImpl的内部类 WindowInputEventReceiver中.

那么WmS是如何传递到ViewRootImpl的呢? 我们来分析..

我们需要知道的是,Touch事件从WmS传递到client 用的并不是IPC机制, 而是内存管道和共享. 上面图中 只有WmS、InputQueue、InputManager、ViewRootImpl 是在framework层中实现的. 其他则是在native层.

在WmS中,InputReaderThread 会不断从EventHub 中取出touch事件,InputDispatchThread分发事件, 然而分发事件实际操作的是InputPublisher.它内部保存了两个指针. 一个是指向服务端的 InputChannel指针,一个是指向ShareMemory(共享内存)的指针,当有事件要分发时,会把事件写入到ShareMemory中. 并向InputChannel传递一个特定的字符串,由InputChannel 将该字符串写入到管道中.

一旦client端的InputChannel从管道中读取到有事件过来.就会通知InputConsumer从ShareMemory中取出事件.并传递到InputQueue中,最后进入ViewRootImpl. 当事件消费完毕,client会回传通知WmS.

以上就是从WmS到client端的大体流程,下面我们就来重点说ViewRootImpl内的事件传递.

当事件传递过来后会被 WindowInputEventReceiver接口到 并进行 一系列的调用, onInputEvent -> enqueueInputEvent  ->  doProcessInputEvents -> deliverInputEvent   我们可以看到,最终会调用deliverInputEvent(QueuedInputEvent q) 这个方法.

在说到deliverInputEvent这个方法前, 我们首先要知道一个概念:

在ViewRootImpl中,有一系列InputStage概念, 每种InputStage可以处理一定的事件类型,它有很多子类 如AsyncInputStage、ViewPreImgInputStage、ViewPostImeInputStage等.当一个InputEvent到来时,ViewRootImpl会找合适的stage来处理. 对于点击事件来说,ViewPostImeInputStage 可以处理. 这时我们来看deliverInputEvent方法.

    private void deliverInputEvent(QueuedInputEvent q) {Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",q.mEvent.getSequenceNumber());if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);}//在ViewRootImpl中,有一系列InputStage(输入舞台事件)概念.//每种InputStage可以处理一定的事件类型.// 如:AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等.// 当一个InputEvent到来时,ViewRootImpl会寻找合适的InputStage来处理.//对于点击事件来说, ViewPostImeInputStage可以处理.//ViewPostImeInputStage可以处理 中有一个processPointerEvent方法.//在该方法中会调用 mView的dispatchPointerEvent方法, mView 就是DecorView.InputStage stage;if (q.shouldSendToSynthesizer()) {stage = mSyntheticInputStage;} else {stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;}if (stage != null) {stage.deliver(q);} else {finishInputEvent(q);}}

可以看到.最终会调用 stage.deliver(q)

     /*** Delivers an event to be processed.*/public final void deliver(QueuedInputEvent q) {if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {forward(q);} else if (shouldDropInputEvent(q)) {finish(q, false);} else {apply(q, onProcess(q));}}

在deliver经过一系列调用后, 会调用onPrucess这个方法. 而 ViewRootImeInputStage 重写了这个方法. 我们来看看它里面是怎么实现的.

   @Overrideprotected int onProcess(QueuedInputEvent q) {if (q.mEvent instanceof KeyEvent) {return processKeyEvent(q);} else {// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();final int source = q.mEvent.getSource();if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {return processPointerEvent(q);} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {return processTrackballEvent(q);} else {return processGenericMotionEvent(q);}}}

可以看到, 在这里最后会调用 processPointerEvent(q) 这个方法.

在processPointerEvent(q) 中, 会调用ViewRootImpl 内部变量 mView.dispatchPointerEvent(event) 这个方法, 看到这里会有很多人问了, mView是什么 ?  它是个DecorView, 是在Activity setContentView后 创建的,最后经过ActivityThread内的 handleResumeActivity 方法 通过 wm.addView, 最后调用了WindowManagerGlobal 内的addView, 在这里会创建ViewRootImpl, 之后会调用它的 setView方法,将DecorView传递进去,并赋值给mView变量.  关于这方面内容,不在详细介绍~

经过上面说明我们知道,mView 是DecorView, 由于DecorView内没有dispatchPointerEvent方法, 所以会调用它的超父类View 内部的 dispatchPointerEvent方法.

public final boolean dispatchPointerEvent(MotionEvent event) {if (event.isTouchEvent()) {return dispatchTouchEvent(event);} else {return dispatchGenericMotionEvent(event);}}

在这里,先判断是否是touchEvent,该方法会调用natvice层的代码. 不在叙述. 我们要知道的是, 这里会调用dispatchTouchEvent方法,而DecorView重写了该方法. 所以会调用到DecorView的dispatchTouchEvent,我们来看看它

  @Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {final Callback cb = getCallback();return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev): super.dispatchTouchEvent(ev);}

在该方法内 首先会调用getCallback()对象. 它实际就是一个Activity, 在ActivityThread内经过handleLaunchActivity ->performLaunchActivity, 在这里会创建activity,并调用activity的attach方法, 在attach方法内.  会创建个 PhoneWindow,并 调用phoneWindow.setCallback(this);然后这里会经过 三个判断, 全部满足则调用 activity的 dispatchToucherEvent, 否则调用 父类的dispatchTouchEvent.  这里其实最终都会调用到 super.dispatchTouchEvent方法.

我们来看看Activity内的 dispatchTouchEvent方法

    /*** Called to process touch screen events.  You can override this to* intercept all touch screen events before they are dispatched to the* window.  Be sure to call this implementation for touch screen events* that should be handled normally.** @param ev The touch screen event.** @return boolean Return true if this event was consumed.*/public boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {onUserInteraction();}//最终会执行到ViewGroup的 dispatchTouchEvent, 如果该方法返回true,则不会执行到自身的onTouchEventif (getWindow().superDispatchTouchEvent(ev)) {return true;}return onTouchEvent(ev);}

第一个if内的方法,onUserInteraction 是个空实现. 我们来看下个if. 如果该方法返回false, 则会调用它自身的onTouchEvent方法.

  /*** Called when a touch screen event was not handled by any of the views* under it.  This is most useful to process touch events that happen* outside of your window bounds, where there is no view to receive it.** @param event The touch screen event being processed.** @return Return true if you have consumed the event, false if you haven't.* The default implementation always returns false.*/public boolean onTouchEvent(MotionEvent event) {if (mWindow.shouldCloseOnTouch(this, event)) {finish();return true;}return false;}

这里会调用 Window类的 shouldCloseonTouch, 如果返回true就会关闭掉当前页. 来看看 shouldCloseonTouch

   /** @hide */public boolean shouldCloseOnTouch(Context context, MotionEvent event) {//如果mCloseOnTouchOutside(对应xml中 android:windowCloseOnTouchOutside) 为true 并且是当事件, 并且down事件在activity范围之外, 返回true//该情况同于Dialogif (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN&& isOutOfBounds(context, event) && peekDecorView() != null) {return true;}return false;}

由注释可知,实际dialog 就是这种形式存在的.  会到Activity的 dispatchTouchEvent内, 如果第二个if返回true,那么结果就为true, 我们看看if内的方法. 会调用PhoneWindow内的superDispatchTouchEvent, 然后会调用DecorView的superDispatchTouchEvent 最终调用到ViewGroup的dispatchTouchEvent(event).

以上.就是事件传递到ViewGroup内的过程.

android touch事件解析 (从wms到viewgroup)相关推荐

  1. android touch事件坐标原点,图解Android:Touch事件传递机制

    前言 Android事件管理机制是一名专业Android研发工程师必须要了解的核心知识之一,深入了解一下该机制无论对我们日常开发还是找工作,乃至于对我们的架构思想都有很大的帮助.Android中我们用 ...

  2. android触摸屏事件,Android Touch事件分析

    Android Touch事件分析 本文将分析Touch事件的传递.很多复杂的功能都需要深刻的处理Touch事件,例如侧边栏,例如图标的拖动换位. 一,Touch事件的执行轨迹 Down->Mo ...

  3. Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  4. Android Touch事件原理加实例分析

    Android中有各种各样的事件,以响应用户的操作.这些事件可以分为按键事件和触屏事件.而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制. ...

  5. Android Touch事件传递机制 二:单纯的(伪生命周期)

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  6. Android Touch事件分发—拦截—处理

    Android Touch事件分发(dispatchTouchEvent)-拦截(onInterceptTouchEvent)-处理(onTouchEvent) 转自:http://www.cnblo ...

  7. Android Touch事件传递

    touch翻译为接触,触摸.我们今天要聊的就是摸的事件. 在Android中了解了Touch事件可以帮助我们解决,ScrollView嵌套ListView,GridView,viewPager滑动冲突 ...

  8. android touch事件无反应,触摸屏 无响应

    (609条消息) android touch事件无反应,android的touch事件分发响应机制_蒙娜lisa的博客-CSDN博客 (609条消息) android touch事件无反应,移动端to ...

  9. Android touch 事件的处理流程

    1.与 touch 事件相关的主要处理方法是: dispatchTouchEvent (onInterceptTouchEvent + onTouchEvent) onInterceptTouchEv ...

最新文章

  1. 重复数据删除(De-duplication)技术研究
  2. IP网络设计系列之-局域网设计
  3. Andorid与webView交互,获取webView选中文字,兼容了iframe
  4. Java substring() 方法
  5. MVVM更容易内存泄露吗?
  6. python受欢迎的原因是什么?
  7. Python数据分析之画图力气pyecharts 制作3D图像!
  8. Hadoop之MapReduce分布式计算
  9. struts2框架概述
  10. 我的MIT代数拓扑笔记
  11. 客户画像中的聚类分析
  12. python写梦幻西游手游脚本_AirtestIDE实践一:梦幻西游手游师门任务自动化
  13. 异步实现商品详情页查询
  14. day10 爬虫导言
  15. 八爪鱼采集百度地图坐标店铺视频教程
  16. 网易云音乐无法正常运行
  17. ROW_NUMBER 和OVER()分组
  18. 续.第一次冲刺之后.
  19. Win10升级Win11必备的5款免费软件
  20. Stunnel 的用法

热门文章

  1. android 源码下载地址链接
  2. AI技术赋能数智化转型,激发企业变革创新
  3. 服务器加30台显示器,30台手机画面同时显示在一个显示器上的解决方案
  4. struts2单选_带Struts的动态单选按钮
  5. python字符串格式化输出
  6. 电商导购CPS,淘宝联盟如何跟单实现用户和订单绑定
  7. 今天一天下午到晚上都在研究如何刷手机,要是被领导知道我帮同学在刷手机系统,非开除我不可。还是贴出来,以后少走弯路吧...
  8. postgresql易学堂_Web优化躬行记(2)——JavaScript
  9. 锐捷亮相2017土耳其ISAF国际安防展
  10. java小算法—球从100米高度自由落下