# 安卓事件传递机制
> 参考文章:[https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation](https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation "https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation")
[](https://www.jianshu.com/p/238d1b753e64?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation)![image.png](https://upload-images.jianshu.io/upload_images/13971762-1594a6044e2eedc5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image.png](https://upload-images.jianshu.io/upload_images/13971762-18aeeb969cd62cd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> DecorView属于View体系,当它调用super.dispatchTouchEvent()方法的时候,实际上是调用ViewGroup的dispatchTouchEvent()函数。
```
//code View.java
public boolean dispatchTouchEvent(MotionEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
if (onFilterTouchEventForSecurity(event)) {
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if (onTouchEvent(event)) {
return true;
}
}
...
return false;
}
```
> **在dispatchTouch()函数中,大致分成以下几个过程:**
>
> 1\. 函数会优先调用onFilterTouchEventForSecurity()方法对事件进行拦截。这个函数是在特定的界面模糊不可点击的情况下使用,一般我们不用理会。
>
> 2\. View会获取OnTouchListener回调接口,并调用回调接口来处理事件。
>
> 3\. 当回调接口不予处理的时候,将调用自己的onTouch()回调来处理
>
> **所以对于View类来说,它的调用过程是:** dispatchTouch( )->OnTouchListener.onTouch( )->onTouch( )
```
//code ViewGroup.java
...
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
cancelAndClearTouchTargets(ev);
resetTouchState();
}
...
```
> 在刚开始执行dispatchTouch的时候,如果当前的事件是一个down事件,ViewGroup会清掉之前所保存的按下状态。调用的方法是cancelAndClearTouchTargets和resetTouchState。比如当前按钮处于按下状态,因为某种原因没有正常反弹,通过cancelAndClearTouchTargets就可以告诉按钮当前状态重置了,可以回弹了。之后,会执行ViewGroup的核心方法:
```
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
//判断是否可以执行onInterceptTouchEvent
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;//判断是否有必要执行onInterceptTouchEvent
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
```
> 这段代码的核心,在于是否调用onInterceptTouchEvent回调方法。一旦onInterceptTouchEvent方法返回true,意味着这个事件需要由当前ViewGroup来处理,也就是把ViewGroup当成View来看,走上述的View事件处理流程,在此不再赘述。那么什么时候调用这个回调方法呢?
**ViewGroup的事件处理过程:**
> dispatchTouch() -> onInterceptTouchEvent -> (View流程) OnTouchListener.onTouch( ) -> onTouch()
### 结论:
* **当ViewGroup决定拦截事件后,后续事件将默认交给它处理并且不会再调用onInterceptTouchEvent方法来判断是否拦截。子View可以通过设置FLAG_DISALLOW_INTERCEPT标志位来不让ViewGroup拦截除ACTION_DOWN以外的事件。**
* **所以我们知道了onInterceptTouchEvent并非每次都会被调用。如果要处理所有的点击事件那么需要选择dispatchTouchEvent方法,而FLAG_DISALLOW_INTERCEPT标志位可以帮助我们去有效的处理滑动冲突**
* Android 事件分发总是遵循 Activity => ViewGroup => View 的传递顺序;
* onTouch() 执行总优先于 onClick()
> 以下图片来源:[https://www.jianshu.com/p/38015afcdb58](https://www.jianshu.com/p/38015afcdb58 "https://www.jianshu.com/p/38015afcdb58")
**Activity 的事件分发示意图**
![image.png](https://upload-images.jianshu.io/upload_images/13971762-1fae1d7abca8cb60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**ViewGroup 事件分发示意图**
![image.png](https://upload-images.jianshu.io/upload_images/13971762-8e7982bda902dc68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**View 的事件分发示意图**
![image.png](https://upload-images.jianshu.io/upload_images/13971762-2c11f50b46c90b47.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**事件分发工作流程总结**
![image.png](https://upload-images.jianshu.io/upload_images/13971762-b2ab59b9259cfa7a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)