一个点击引起的世界大战
有一个WMS(WindowManagerService)
的大管家掌管着Android系统的键盘消息,他有个属性叫mInputManager(IMS,InputManagerService)
,是Android的输入管理器,属于Java层输入管理器,同时他指向着C++层中的输入管理器InputManager
来监控系统的键盘消息(来自《Android系统源代码情景分析 第三版》)
当我们在屏幕上的点击,经过WMS,IMS,到native层,最后会回调到Java层的InputEventReceiver.dispatchInputEvent(int seq, InputEvent event, int displayId)
,一步步调用到Activity.dispatchTouchEvent()
- 序列图
-
InputEventReceiver.dispatchInputEvent(int seq, InputEvent event, int displayId)
// Called from native code. @SuppressWarnings("unused") private void dispatchInputEvent(int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event, displayId); }
-
InputEventReceiver
是abstract class
,在ViewRootImpl
中有个内部类叫WindowInputEventReceiver
继承InputEventReceiver
final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); } @Override public void onInputEvent(InputEvent event, int displayId) { // native 回调在这里 enqueueInputEvent(event, this, 0, true); } ... }
-
onInputEvent()
方法中调用enqueueInputEvent()
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); // Always enqueue the input event in order, regardless of its time stamp. // We do this because the application or the IME may inject key events // in response to touch events and we want to ensure that the injected keys // are processed in the order they were received and we cannot trust that // the time stamp of injected events are monotonic. 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); // 上面的传参是true,调用doProcessInputEvents() if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } }
-
进入
doProcessInputEvents
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); long eventTime = q.mEvent.getEventTimeNano(); long oldestEventTime = eventTime; if (q.mEvent instanceof MotionEvent) { MotionEvent me = (MotionEvent)q.mEvent; if (me.getHistorySize() > 0) { oldestEventTime = me.getHistoricalEventTimeNano(0); } } mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime); // 到这 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); } }
-
进入
deliverInputEvent()
private void deliverInputEvent(QueuedInputEvent q) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", q.mEvent.getSequenceNumber()); if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); } InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (stage != null) { // 到这 stage.deliver(q); } else { finishInputEvent(q); } }
-
这里的
stage
是ViewPostImeInputStage
继承InputStage
/** * Delivers post-ime input events to the view hierarchy. */ final class ViewPostImeInputStage extends InputStage { public ViewPostImeInputStage(InputStage next) { super(next); } @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); } } } ... private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; mAttachInfo.mUnbufferedDispatchRequested = false; mAttachInfo.mHandlingPointerEvent = true; // 这里的mView是DecorView boolean handled = mView.dispatchPointerEvent(event); maybeUpdatePointerIcon(event); maybeUpdateTooltip(event); mAttachInfo.mHandlingPointerEvent = false; if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) { mUnbufferedInputDispatch = true; if (mConsumeBatchedInputScheduled) { scheduleConsumeBatchedInputImmediately(); } } return handled ? FINISH_HANDLED : FORWARD; } ... }
-
dispatchPointerEvent
在view中实现/** * Dispatch a pointer event. *
* Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches * and should not be expected to handle other pointing device features. *
* * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. * @hide */ public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { // 调用dispatchTouchEvent return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } -
dispatchTouchEvent
,注意这里的Window.Callback就是Activity,@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); }
到
Activity.dispatchTouchEvent
Activity.dispatchTouchEvent()
之后就是我们熟悉的事件分发了
详情见Android事件分发流程(API-27)(二)
- 参考资料
- 《Android系统源代码情景分析 第三版》
- 从你触摸屏幕开始分析android触摸事件分发