网上有很多文章分析dispatchTouchEvent,onTouch,onTouchEvent这三个事件分发的流程,很少看到对事件源头分发的分析。简单分析下事件源头的分发。
先看对触摸消息的分发。
当屏幕收到触摸消息,系统会把触摸消息分发给Activity的DecorView的dispatchTouchEvent,
public class PhoneWindow extends Window implements MenuBuilder.Callback {
//DecorView是PhoneWindow的内部类
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Callback cb = getCallback();//Callback就是Activity
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
}
}
}
上面的Callback就是Activity,Activity实现了Window.Callback这个接口。
可以看到如果Callback不为空,就将消息分发给Activity,否则调用super.dispatchTouchEvent(ev),因为DecorView是个FrameLayout,于是可以走一般的ViewGroup流程,但是这里Callback一般不为空,于是消息给了Activity的dispatchTouchEvent。
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback {
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();//这个方法是空的
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);//ViewGroup不消耗事件,调用onTouchEvent
}
}
因为onUserInteraction方法是空的,走到下面getWindow().superDispatchTouchEvent(ev)。
getWindow()就是PhoneWindow,
public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
}
}
上面的传递,最终调用到decorView的super.dispatchTouchEvent,就是熟悉的ViewGroup的dispatchTouchEvent方法。
总结上面的流程:
1、消息先传递到DecorView
2、因为Callback不为空,DecorView将消息传递给了Activity
3、在Activity的dispatchTouchEvent里,先把消息给依DecorView为根的ViewGroup,如果ViewGroup不消耗事件,则调用Activity的onTouchEvent。
硬件 -> ViewRootImpl -> DecorView -> PhoneWindow -> Activity。
在第一步中是谁将消息传递给DecorView的呢?答案是ViewRoot。ViewRootImpl是ViewRoot的实现类,里面有个成员变量mView,这个就是DecorView。