クリックイベントがActivityにどのように渡されるか

6539 ワード

イベントはWindowからActivityに渡され、windowglobleのaddviewメソッドではInputChannel、InputQueue、WindowInputEventReceiverが作成され、クリックイベントのメッセージを受信します.
ViewRootImplには方法があります
 private void scheduleProcessInputEvents() {
        if (!mProcessInputEventsScheduled) {
            mProcessInputEventsScheduled = true;
            Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
            msg.setAsynchronous(true);
            mHandler.sendMessage(msg);
        }
    }

どうやって処理されたか見てみましょう
 case MSG_PROCESS_INPUT_EVENTS:
                mProcessInputEventsScheduled = false;
                doProcessInputEvents();
                break;

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);

            deliverInputEvent(q);
        }
private void deliverInputEvent(QueuedInputEvent q) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
        try {
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
            }

            InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
            if (stage != null) {
                stage.deliver(q);
            } else {
                finishInputEvent(q);
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

ViewRootImplでは、AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStageなど、各InputStageが一定のイベントタイプを処理できるという概念がある.InputEventが来ると、ViewRootImplは適切なInputStageを探して処理します.クリックイベントについては、ViewPostImeInputStageが処理できます.ViewPostImeInputStageには、mViewのdispatchPointerEventメソッドを呼び出すprocessPointerEventメソッドがあります.ここのmViewは実はDecorViewです.
 private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;

            // Translate the pointer event for compatibility, if needed.
            if (mTranslator != null) {
                mTranslator.translateEventInScreenToAppWindow(event);
            }

            // Enter touch mode on down or scroll.
            final int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
                ensureTouchMode(true);
            }

            // Offset the scroll position.
            if (mCurScrollY != 0) {
                event.offsetLocation(0, mCurScrollY);
            }

            // Remember the touch position for possible drag-initiation.
            if (event.isTouchEvent()) {
                mLastTouchPoint.x = event.getRawX();
                mLastTouchPoint.y = event.getRawY();
            }
            return FORWARD;
        }

DecorViewがViewから継承されているため、ViewのdispatchPointerEventを見てみましょう.
  public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }

そしてDecorViewのdispatchTouchEventを呼び出しました
  @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            final Callback cb = getCallback();
            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
                    : super.dispatchTouchEvent(ev);
        }

ここでcbはActivityオブジェクトです.