在事件分发和处理的过程中,我们比较熟悉方法有:比如dispatchTouchEvent,做事件分发;onTouchEvent,onTouchListener用来处理各类型的事件等,但是事件到底是从哪里开始的呢?又是怎么传递到dispatchTouchEvent方法,这些我们都没有关心过,今天就带着大家简单过一下源码
相信大家应该还没忘记ViewRootImpl这个类,在上篇博客Android-UI的渲染过程中提到过它的setView方法,主要解释了里面requestLayout方法,今天我们看一下其他的内容:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
.....
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
......
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
.....
}
}
}
第17~26行:我们可以看见一个关键的类InputStage以及它的子类类,这些类表示的就是点击的类型。这里的类型有很多中,关于这些类型的介绍,我推荐大家一篇文章Android-InputStage,而我们这次所说的点击事件类型对应的InputStage是ViewPostImeInputStage
第11行:创建了一个WindowInputEventReceiver对象,当发生点击事件的时候,这个就会执行到这个类的onInputEvent方法,我们看一下这个方法
void enqueueInputEvent(InputEvent event) {
enqueueInputEvent(event, null, 0, false);
}
查看enqueueInputEvent方法
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
....
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
这里就是做了一个线程调度,但是最终都会执行到doProcessInputEvents方法中
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
....
deliverInputEvent(q);
}
....
}
我留下了关键方法deliverInputEvent,我们进入看一下
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
...
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
....
if (stage != null) {
handleWindowFocusChanged();
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
第6行:InputStage对象和我们上面说的InputStage对应,这里是ViewPostImeInputStage
第16行:deliver在ViewPostImeInputStage中没有被复写,所以我们查看的InputStage的deliver方法
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
apply(q, onProcess(q));
}
}
这里会执行到else的方法体重,我们在apply方法中看见onProcess方法,而这个方法在ViewPostImeInputStage中被复写,我们查看一下:
@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
会执行到第8行的processPointerEvent方法,我们查看:
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
....
boolean handled = mView.dispatchPointerEvent(event);
....
return handled ? FINISH_HANDLED : FORWARD;
}
到这里,我们要注意,我们目前看的这些类都是ViewRootImpl的内部类,而这里的mView就是ViewRootImpl中的mView。相信大家应该还没忘记,ViewRootImpl的mView是DecorView,我们查看DecorView的dispatchPointerEvent方法,我们在DecorView中并没有找到这个方法,那么这个类一定是在它的父类,或者父类的父类里,其实是在View中,我们查看:
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
dispatchTouchEvent方法在DecorView中有复写,我们查看DecorView的此方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
cb这个对象其实就是Activity,这里执行了Activity的dispatchTouchEvent方法,继续查看
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
这里存在了两种情况,我们先看第一种,也就是getWindow().superDispatchTouchEvent方法返回true的情况,getWindow()估计大家都不陌生了,就是PhoneWindow对象,我们查看它的superDispatchTouchEvent方法
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
mDecor是DecorView,让了一圈有回到了这个类,我们继续查看它的superDispatchTouchEvent方法
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
DecorView的父类是FrameLayout,这个类是没有复写dispatchTouchEvent方法,也就是没有做事件的处理,实际上是ViewGroup处理的。
其实到这里,事件的分发的第一个阶段就结束了,基本上捋清了事件是如何从Activity传递到DecorView的过程。
我们刚刚在Activity的dispatchTouchEvent方法中说,有两种情况,也就是说如果getWindow().superDispatchTouchEvent方法为false时候,是第二种情况,表示每一个View或ViewGroup都不对事件进行分发拦截,那么由最上层的View进行事件的处理,也就是执行Activity的onTouchEvent方法。
关于事件分发的第二阶段,也就是事件是如何在View树中传递的,我会在下一篇博客介绍。