クリックイベントがActivityにどのように渡されるか
6539 ワード
イベントはWindowからActivityに渡され、windowglobleのaddviewメソッドではInputChannel、InputQueue、WindowInputEventReceiverが作成され、クリックイベントのメッセージを受信します.
ViewRootImplには方法があります
どうやって処理されたか見てみましょう
doProcessInputEventsメソッドが呼び出されます
ViewRootImplでは、AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStageなど、各InputStageが一定のイベントタイプを処理できるという概念がある.InputEventが来ると、ViewRootImplは適切なInputStageを探して処理します.クリックイベントについては、ViewPostImeInputStageが処理できます.ViewPostImeInputStageには、mViewのdispatchPointerEventメソッドを呼び出すprocessPointerEventメソッドがあります.ここのmViewは実はDecorViewです.
DecorViewがViewから継承されているため、ViewのdispatchPointerEventを見てみましょう.
そしてDecorViewのdispatchTouchEventを呼び出しました
ここでcbはActivityオブジェクトです.
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オブジェクトです.