
我们都知道处理Android的手势问题时,都是通过Activity的 onTouchEvent 事件来处理的,那么今天我们来看看手势信息是从哪里传递来的呢
通过我们之前的Android View绘制流程中,我们知道在ViewRootImpl的setView方法中,我们生成了一个WindowInputEventReceiver对象,这个对象就是用来监听输入事件的。
ViewRootImpl类
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
......
if (inputChannel != null) {
......
//注册一个输入事件监听,当有输入事件时,会触发它的onInputEvent事件,见下方
mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
Looper.myLooper());
......
}
}
}
}
WindowInputEventReceiver 类
@Override
public void onInputEvent(InputEvent event) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
List processedEvents;
try {
processedEvents =
mInputCompatProcessor.processInputEventForCompatibility(event);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (processedEvents != null) {
if (processedEvents.isEmpty()) {
// InputEvent consumed by mInputCompatProcessor
finishInputEvent(event, true);
} else {
for (int i = 0; i < processedEvents.size(); i++) {
//将输入事件插入队列
enqueueInputEvent(
processedEvents.get(i), this,
QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
}
}
} else {
enqueueInputEvent(event, this, 0, true);
}
}
2. 加入输入事件消息队列
ViewRootImpl类
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
......
//插入队列中
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
if (processImmediately) {
//派发输入事件
doProcessInputEvents();
} else {
//发送异步消息,最终也是调用doProcessInputEvents()
scheduleProcessInputEvents();
}
}
3. 派发输入事件
ViewRootImpl类
//派发消息队列的输入事件
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
//派发队列中的某一个事件
deliverInputEvent(q);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
ViewRootImpl类
//派发输入事件
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getId());
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
+ Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
+ q.mEvent.getEventTimeNano() + " id=0x"
+ Integer.toHexString(q.mEvent.getId()));
}
try {
if (mInputEventConsistencyVerifier != null) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
try {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
//InputStage可以理解为输入事件的各个阶段,下面有介绍,采用的是责任链模式
InputStage stage;
//选择责任链的入口
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (q.mEvent instanceof KeyEvent) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
try {
mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
if (stage != null) {
handleWindowFocusChanged();
//分发事件
stage.deliver(q);
} else {
finishInputEvent(q);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
4. InputStage类
关于InputStage有很多子类,如下
责任链模式图如下
用一张图来描述InputStage的处理流程如下
对于屏幕的点击事件,我们是在ViewPostImeInputStage中的onProcess方法处理的
@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);
}
}
}
接下来分析processPointerEvent()方法,我们发现调用了DecorView的dispatchPointerEvent()
ViewRootImpl类
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
......
boolean handled = mView.dispatchPointerEvent(event);
......
}
我们在DecorView中没有找到dispatchPointerEvent()方法,进而一步一步从父类中找,终于,在View类中找到了dispatchPointerEvent()方法
View类
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
//调用了dispatchTouchEvent,DecorView中覆写了该方法
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
DecorView类
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
// 将事件派发到了 Window.Callback 接口的实现类,也就是Activity类中
// (Activity的attach方法中,将Activity对象设置为Window的Callback)
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
5. 分发到Activity类中
接下来分析Activity的dispatchTouchEvent()
Activity类
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// 传递给Window处理
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
6. 分发到PhoneWindow类中
PhoneWindow.java
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
//继而又传递给DecorView处理
return mDecor.superDispatchTouchEvent(event);
}
7. 分发到DecorView类中,最终分发到ViewGroup中
DecorView.java
public boolean superDispatchTouchEvent(MotionEvent event) {
//继而又传递给了ViewGroup处理
return super.dispatchTouchEvent(event);
}
至此,我们的手势终于分发到了ViewGroup中。
总结用一张图总结手势事件的来源
文中部分图片借鉴自Android Framework 输入子系统 InputStage解读这篇文章。