早上看到事件分发的一个讨论:

那么事件到底是先到DecorView还是先到Window(Activity,Dialog)的。
- touch相关事件在DecorView,PhoneWindow,Activity/Dialog之间传递的顺序是什么样子的?
- 为什么要按照1这么设计?
更多问答 >>
-
每日一问 RecyclerView卡片中持有的资源,到底该什么时候释放?
2020-03-10 21:11 -
每日一问 | 很久以前有Activity.onResume就是界面可见的说法,这种说法错了多少?
2020-03-15 23:10 -
每日一问 今天考察下 Fragment 相关两个不常见 API
2020-03-19 00:55 -
每日一问 LifeCycle 对于 Lifecycle.Event 为啥不直接分发,而是通过 Lifecycle.State 中转?
2020-04-19 14:42 -
每日一问 ViewPager 这个流传广泛的写法,其实是有问题的!
2020-03-26 00:10 -
每日一问 Android有个GestureDetector很好用?那么你知道它内部是如何实现的吗?
2020-03-02 23:56 -
每日一问 很多时候我们说单例实现方式会提到「枚举实现」,那么枚举底层是如何实现的呢?
2020-02-23 22:18 -
2020-02-02 17:17
-
每日一问 “你这个布局可以在进入这个页面之前预加载,这样页面渲染就快了”可能有什么潜在的问题吗?
2020-01-20 01:05 -
每日一问 “别慌,你 post 一个 Runnable ,在下一帧就可以拿到了。”这种说法对吗?
2020-01-20 01:05

事件先到DecorView
Input系统
当用户触摸屏幕或者按键操作,首次触发的是硬件驱动,驱动收到事件后,将该相应事件写入到输入设备节点,这便产生了最原生态的内核事件。接着,输入系统取出原生态的事件,经过层层封装后成为KeyEvent或者MotionEvent ;最后,交付给相应的目标窗口(Window)来消费该输入事件。
1、当屏幕被触摸,Linux内核会将硬件产生的触摸事件包装为Event存到/dev/input/event[x]目录下。2、Input系统—InputReader线程:loop起来让EventHub调用getEvent()不断的从/dev/input/文件夹下读取输入事件。然后转换成EventEntry事件加入到InputDispatcher的mInboundQueue。3、Input系统—InputDispatcher线程:从mInboundQueue队列取出事件,转换成DispatchEntry事件加入到connection的outboundQueue队列。再然后开始处理分发事件 (比如分发到ViewRootImpl的WindowInputEventReceiver中),取出outbound队列,放入waitQueue.4、Input系统—UI线程:创建socket pair,分别位于”InputDispatcher”线程和focused窗口所在进程的UI主线程,可相互通信。这里只说大概,详情请看gityuan的这篇文章Input系统—事件处理全过程,文章3.3.3小节讲的是input系统事件从Native层分发Framework层的InputEventReceiver.dispachInputEvent()。
Framework层
ViewRootImpl.WindowInputEventReceiver
Native层通过JNI执行Framework层的InputEventReceiver.dispachInputEvent(),而真正调用的是继承了InputEventReceiver的ViewRootImpl.WindowInputEventReceiver。所以这里执行的WindowInputEventReceiver的dispachInputEvent():
ViewRootImpl
ViewRootImpl.ViewPostImeInputStage
前面事件会派发到ViewRootImpl.ViewPostImeInputStage中处理,它的父类InputStage.deliver()方法会调用apply()来处理Touch事件:
DecorView
如果你熟悉安卓的Window,Activity和Dialog对应的ViewRootImpl成员mView就是DecorView,View的dispatchPointerEvent()代码如下:
因为DecorView继承FrameLayout,上面所以会调用DecorView的dispatchTouchEvent():
上面Window.Callback都被Activity和Dialog实现,所以变量cb可能就是Activity和Dialog。
Activity
当上面cb是Activity时,执行Activity的dispatchTouchEvent():
如果你熟悉安卓的Window,Activity的getWindow()拿到的就是PhoneWindow,下面是PhoneWindow的代码:
下面是DecorView.superDispatchTouchEvent()代码:
流程图
为什么要DecorView -> Activity -> PhoneWindow -> DecorView传递事件
解耦! ViewRootImpl并不知道有Activity这种东西存在!它只是持有了DecorView。所以,不能直接把触摸事件送到Activity.dispatchTouchEvent();那么,既然触摸事件已经到了Activity.dispatchTouchEvent()中了,为什么不直接分发给DecorView,而是要通过PhoneWindow来间接发送呢?因为Activity不知道有DecorView!但是,Activity持有PhoneWindow ,而PhoneWindow当然知道自己的窗口里有些什么了,所以能够把事件派发给DecorView。在Android中,Activity并不知道自己的Window中有些什么,这样耦合性就很低了。我们换一个Window试试?不管Window里面的内容如何,只要Window任然符合Activity制定的标准,那么它就能在Activity中很好的工作。当然,这就是解耦所带来的扩展性的好处。
请问一下,为啥先是DecorView,后面又回到DecorView了,此处为啥要这样设计。
上面已经说了“为什么要DecorView -> Activity -> PhoneWindow -> DecorView传递事件”
楼主您好,这样看,Activity持有一个Window对象,ViewRootImpl中持有的是DecorView,DecorView中可以拿到Activity中的window回调; 当事件由硬件传递到 ...查看更多
楼主您好,这样看,Activity持有一个Window对象,ViewRootImpl中持有的是DecorView,DecorView中可以拿到Activity中的window回调; 当事件由硬件传递到Framework层时,首先传递给ViewRootImpl,再由ViewRootImpl传递给他持有的DecorView,在DecorView中回调Activity实现的Window回调接口传递到Activity,Activity又getWindow传递,window在传递给DecorView,在具体分发到下面的子View? 所以传递的机制是:ViewRootImpl->DecorView->Activity->Window->DecorView->具体子View,是否这样理解?
是的
还有个疑问,Window中是应该持有一个DecorView,但是在通过WindowManager添加的时候,会生成一个ViewRootImpl,将DecorView放入其中,这个时候Window还算直 ...查看更多
还有个疑问,Window中是应该持有一个DecorView,但是在通过WindowManager添加的时候,会生成一个ViewRootImpl,将DecorView放入其中,这个时候Window还算直接持有DecorView吗
每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,所以Window还不算直接持有DecorView,建议您看一下《an ...查看更多
每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,所以Window还不算直接持有DecorView,建议您看一下《android开发艺术探索》里的第8章关于Window和WindowManager的内容。
ViewRootImpl 是知道DecorView 存在的,也就是ViewRootImpl 中的mView,是可以调用super.dispatchTouchEvent的,为什么要再转这么一圈非要传给A ...查看更多
ViewRootImpl 是知道DecorView 存在的,也就是ViewRootImpl 中的mView,是可以调用super.dispatchTouchEvent的,为什么要再转这么一圈非要传给Activity呢?是不是还有其他的作用?
要知道有什么作用,可以反过来思考,如果TouchEvent不传递到Window.Callback(即Activity或Dialog),他们会缺少什么功能? 先看Activity中:在Activity. ...查看更多
要知道有什么作用,可以反过来思考,如果TouchEvent不传递到Window.Callback(即Activity或Dialog),他们会缺少什么功能? 先看Activity中:在Activity.dispatchTouchEvent方法中,调用了两个方法:onUserInteraction,onTouchEvent。通过文档可以知道,onUserInteraction可以用于判断用户正和你的Activity发生交互;在onTouchEvent中,调用了mWindow.shouldCloseOnTouch,决定是否要关闭页面,但是我暂时没想到具体应用场景。 再看Dialog中:也是在dispatchTouchEvent中,调用了onTouchEvent。我相信如果你看了onTouchEvent中的代码,一下就明白了。没错,Dialog的点击布局外的空白区域,自动dismiss的功能,正式借助了onTouchEvent来实现的。
你这个总结真好 一看就懂
为什么最后要绕一圈从view到activity再回到view,我的理解是android希望给activity一个优先处理到机会,因为不是所有到用户界面都会去自定义view或者复写view的事件处理方法 ...查看更多
为什么最后要绕一圈从view到activity再回到view,我的理解是android希望给activity一个优先处理到机会,因为不是所有到用户界面都会去自定义view或者复写view的事件处理方法,优先给到activity处理机会可以节省那些想处理页面事件的开发者的开发成本
DecorView->Activity->PhoneWindow->DecorView
参考文章:
https://www.jianshu.com/p/faedef1910fe
https://www.jianshu.com/p/f05d6b05ba17http://gityuan.com/2016/12/10/input-manager/2.正题
2.1基本知识和概念
整个Input机制与下面几个类有关。
EventHub,它主要是利用Linux的inotify和epoll机制,监听设备事件:包括设备插拔及各种触摸、按钮事件等,可以看做是一个不同设备的集线器,主要面向的是/dev/input目录下的设备节点,比如说/dev/input/event0上的事件就是输入事件,通过EventHub的getEvents就可以监听并获取该事件。EventHub类:
EventHub得到RowEvent之后,交给InputReader进行加工成我们需要的KeyEvent。并将Event传递给InputDispatcher,InputReader类:
InputDispatcher负责将event传递给上层。InputDispatcher类:2.2 如何将事件分发给上层应用
ViewRootImp#setView
1.创建Channel2.将Channel传递给WMS3.创建WindowInputEventReceiver4.创建InputStage 责任链设计模式上图并不是包装者模式,而是地地道道的责任链模式。构造方法中指定的对象作为是为Next赋值的。
最终执行到 ViewPostImeInputStage#processPointerEvent。进而走了DecorView#dispatchPointerEvent方法。
DecorView#dispatchPointerEvent最终会调用到
其中WindowCallBack.被Activity实现。所以会走进Activity#dispatchTouchEvent。
activity的getWindow() 就是我们的PhoneWindow。而PhoneWindow又是调用的。DecorView# dispatchTouchEvent方法 进入了 我们熟悉的事件传递过程。
ps技巧:Log.getStackTraceString(new Throwable()) 打印堆栈,帮我们分析函数调用过程
事件顺序:
1.DecorView。ViewRootImpl事件下发到DecorView2.Activity 。在decorView的dispatchTouchEvent中通过Window的getCallback()拿到Window.Callback的实现类。activity实现了Window.Callback。并且在activity的attach中设置callback为当前activity3.Window。在activity的dispatchTouchEvent调用window的 superDispatchTouchEvent()4.DecorView 在PhoneWindow中superDispatchTouchEvent调用的是DecorView的superDispatchTouchEvent方法。设计原因:老板:安卓部门,我有个想法,有这些功能,你让你们部门实现一下
安卓经理:小张,你是技术大拿,你把这活儿干一下。小张:小李,咱部门就咱俩,你也了解一下。经理我打算这么干。安卓经理:好,干吧666