本文适用于对Android事件分发机制有一定基础的开发者阅读,主要是通过对Activity类中的事件分发、事件消费的源代码进行解析以达到完全理解其原理的目的
- (一)Android事件分发机制 - View篇
- (二)Android事件分发机制 - ViewGroup篇
- (三)Android事件分发机制 - Activity篇
- (四)Android事件分发机制 - 总结篇
当一个点击操作发生时,事件最先传递给当前的Activity
,由Activity
的dispatchTouchEvent
来进行事件的分发,接下来我们通过源代码(基于Android6.0)看看这个方法内部到底做了哪些事情。
1、Activity#dispatchTouchEvent源码解析
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
-
首先判断MotionEvent是不是ACTION_DOWN,如果是的话,执行onUserInteraction()方法:
// 空方法,让子类实现 public void onUserInteraction() { // 当此activity在栈顶时,触屏点击按home,back,menu键等都会触发此方法。 // 下拉statubar、旋转屏幕、锁屏不会触发此方法 // 所以它会用在屏保应用上,因为当你触屏机器 就会立马触发一个事件,而这个事件又不太明确是什么,正好屏保满足此需求。 }
-
getWindow()会返回PhoneWindow对象(PhoneWindow类是Window抽象类的唯一实现子类),调用PhoneWindow#superDispatchTouchEvent(ev):
@Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
-
mDecor是DecorView的实例,是视图的顶层View。DecorView继承自FrameLayout,那么它的父类就是ViewGroup了,而super.dispatchTouchEvent(event)方法,其实就应该是ViewGroup的dispatchTouchEvent()方法
// This is the top-level view of the window, containing the window decor. private DecorView mDecor; public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { ... }
小结
- 当一个点击操作发生时,事件的传递顺序为:
Activity
->Window
->DecorView
,DecorView一般就是当前界面的底层容器(即setContentView所设置的View的父容器)
2、Activity#onTouchEvent源码解析
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
shouldCloseOnTouch
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
// 判断mCloseOnTouchOutside标记及是否为ACTION_DOWN事件
// 同时判断event的x、y坐标是不是超出Bounds,
// 然后检查DecorView是否为空
if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
&& isOutOfBounds(context, event) && peekDecorView() != null) {
return true;
}
return false;
}
小结
- 一个点击操作要是没有被Activity下的任何View处理,即顶层
DecorView
的dispatchTouchEvnent()
方法返回false
的话,则Activity
的onTouchEvent()
方法会被调用。