Android事件分发小结
******** ******** 第一部分: 介绍说明 ******** ********
个人感觉在做交互的时候, 对于Android的按键分发的理解还是比较重要的.
这些内容在<深入理解Android> <Android系统源代码情景分析> 还有一些博客内容中都有写到.
最近想着要仔细的了解一下整体的分发机制, 并且希望能真实的应用在项目中, 所以看了一下InfoQ网站的这篇文章, 感觉写的还不错, 个中有些地方我觉得说的不是很清晰, 但是整体思路自己感觉是理清楚了. 如果发现我理解的有错误, 希望能得到各位的指点(T_T不然会一直错下去的).
相关参考资料:
******** ******** ******** ********
与按键分发有关的类: Activity, View, Window(ViewGroup继承自View, 自定义视图继承自View. ViewGroup特别的有onInterceptTouchEvent()方法, 该方法位于)
Activity相关函数:
dispatchTouchEvent
onTouchEvent
View相关函数
dispatchTouchEvent
onTouch
onTouchEvent
onClick
ViewGroup相关函数
dispatchTouchEvent
onInterceptTouchEvent
onTouch
OnTouchEvent
onClick
******** ******** 按键分发实现细节 ******** ********
====>>>> Activity中的按键分发细节:
boolean dispatchTouchEvent() { // Window::superDispatchTouchEvent(MotionEvent ev)方法由系统实现 // 该方法个人感觉存在于PhoneWindow.java类中, 但是文章中没有写的很清楚. 甚至我觉得是有误导... 需要再斟酌. // 个人猜测该方法主要用于获取xml文件解析出来的View, 通过区分ViewGroup和普通View, 再执行对应的按键分发逻辑. if (getWindow().superDispatchTouchEvent(MotionEvent::ev)) { // 这里表明, 如果dispatchTouchEvent函数返回true, 则表示子类消费过触摸事件 // 如果子类没有消费过触摸事件, 则执行onTouchEvent()方法 return true ; } else { return onTouchEvent(MotionEvent::ev) ; } }
总结, 如果子类的dispatchTouchEvent(MotionEvent ev)方法返回了true, 则Activity不再处理该触摸事件. 否则Activity将触摸事件传递给Activity::onTouchEvent(MotionEvent ev)方法处理. 该方法是触摸事件的终点.
====>>>> View中的按键分发细节
// Activity会先将触摸事件下发到视图控件中 // 触摸事件的入口为dispatchTouchEvent()函数 Window::superDispatchTouchEvent(MotionEvent ev) { // View处理触摸事件的入口, 也是唯一的入口(个人怎么理解的, 不保证正确性) // 其实这里也应该有个遍历, 如果是ViewGroup, 需要先探测所有自孩子的处理结果. public boolean dispatchTouchEvent(MotionEvent ev) { // 对于ViewGroup, 需要先查看是否拦截当前触摸事件, if (this instanceof ViewGroup) { if (!onInterceptTouchEvent()) { for (int i = 0 ; i < getChildCount() ; i++) { if (getChildAt(i).dispatchTouchEvent()) { return true ; } } } } // 这里说明触摸事件监听优先于onTouchEvent并且可以拦截按键分发链条, 从而阻止onTouchEvent函数的执行 if (null != mTouchListener && mTouchListener.onTouch(MotionEvent::ev)) { return true ; } if (onTouchEvent(MotionEvent::ev)) { return true ; } return false ; } } public boolean View::onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_UP) { …. return performClick() ;// 该处为猜测 } } public boolean View::performClick() { if (null != onClickListener) { return true ; } return false ; }
******** ******** 总结 ******** ********
- 事件分发的起始点是Activity::dispatchTouchEvent(MotionEvent ev);
- dispatchTouchEvent(MotionEvent ev)将事件处理传递给onTouchListener和onTouchEvent()方法, 都返回false表示没有消费
- 如果是ViewGroup在dispatchTouchEvent()执行消费逻辑前, 需要递归调用子孩子的dispatchTouchEvent()方法查看子孩子是否消费该事件
- onTouchEvent()方法中通过performClick()方法执行了onClickListner的onClick事件
******** ******** END ******** ********