触摸事件分发流程详解(二):事件发送和接受

InputDispatch中的发送部分(待补充)
继续接着上篇文章分析NativeInputEventReceiver中的

NativeInputEventReceiver中的handleEvent()

建立好channel之后,就是通信了。从InputDispatcher从InBoundQueue队列头中取出事件,然后通过将中将消息发出来了,ViewRootImpl通过就是NativeInputEventReceiver中的handleEvent()方法。

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
    }
.................
    return 1;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    ScopedLocalRef<jobject> receiverObj(env, NULL);
    bool skipCallbacks = false;
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
1、这里通过inputConsumer的counsume方法将输入invent事件转为native的inputEvent;
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
        ....................
        if (!skipCallbacks) {
        ....................
            jobject inputEventObj;
            switch (inputEvent->getType()) {
2、根据native层的inputEvent中的type类型,区分是keyEvent还是motionEvent,然后分别转为不同java对象inputEventObj 。
            case AINPUT_EVENT_TYPE_KEY:
                inputEventObj = android_view_KeyEvent_fromNative(env,
                        static_cast<KeyEvent*>(inputEvent));
                break;
            case AINPUT_EVENT_TYPE_MOTION: {
                MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
                if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch){
                    *outConsumedBatch = true;
                }
                inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
                break;
            }
3、最后,如果java层的inputEvent对象创建成功,就把该对象通过InputEventReceiver中dispatchInputEvent方法分发到java层去。
            if (inputEventObj) {
                if (kDebugDispatchCycle) {
                    ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
                }
                env->CallVoidMethod(receiverObj.get(),
//这个gInputEventReceiverClassInfo其实就是WindowInputEventReceiver的父类InputEventReceiver
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                if (env->ExceptionCheck()) {
                    ALOGE("Exception dispatching input event.");
                    skipCallbacks = true;
                }
                env->DeleteLocalRef(inputEventObj);
            } else {
                ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
                skipCallbacks = true;
            }
        }
    }
}

WindowInputEventReceiver的onInputEvent()
WindowInputEventReceiver的作用:
1、通过父类InputEventReceiver的dispatchInputEvent()方法接受InputEvent事件;
2、通过onInputEvent()方法启动InputStage责任链并传递InputEvent事件。

public void onInputEvent(InputEvent event) {
    enqueueInputEvent(event, this, 0, true);
}
void enqueueInputEvent(InputEvent event,
        InputEventReceiver receiver, int flags, boolean processImmediately) {
    adjustInputEventForCompatibility(event);
1、首先创建一个QueueInputEvent,然后将它添加到队尾
    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);
2、添加结束就立即执行,这里传入的是true
    if (processImmediately) {
        doProcessInputEvents();
    } else {
        scheduleProcessInputEvents();
    }
}
3、doProcessInputEvents的作用就是while循环分发所有的InputEvent事件。分发过程是调用7个InputStage实现类,通过责任链的方式一次传递的。
void doProcessInputEvents() {
    while (mPendingInputEventHead != null) {
        QueuedInputEvent q = mPendingInputEventHead;
        .......................
        deliverInputEvent(q);
    }
}
4、其中ViewPostImeInputStage是Activity和View的的事件处理InputStage对象的实现类。执行方法是onProcess()。
ViewPostImeInputStage的onProcess()
protected int onProcess(QueuedInputEvent q) {
1、首先区分是KeyEvent还是TouchEvent。
    if (q.mEvent instanceof KeyEvent) {
        return processKeyEvent(q);
    } else {
2、然后区分是是触摸还是轨迹球还是生成器
        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;
3、这个因为不是鼠标输入,因此View就是setView方法中传入的mView,也就是DecorView
    final View eventTarget =
            (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
                    mCapturingView : mView;
    mAttachInfo.mHandlingPointerEvent = true;
4、这句话就很眼熟了,执行eventTarget的dispatchPointerEvent;返回分发结果:handled。这里eventTargt就是这里子类对应的是viewtree的根视图:DecorView,dispatchPointEvent方法在View中,dispatchPointEvent方法又调用了DecorView的dispatchTouchEvent();
    boolean handled = eventTarget.dispatchPointerEvent(event);
    .................
    return handled ? FINISH_HANDLED : FORWARD;
}
5、Activity和Dialog都有mWindow.getCallBack回调,这里调用的是Activity的dispatchTouchEvent方法。之后,就是就开始了触摸事件分发。
public boolean dispatchTouchEvent(MotionEvent ev) {
    final Window.Callback cb = mWindow.getCallback();
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

总结:
在建立完InputChannel后,接受信息并传递到开始事件分发主要经过4个步骤:

  1. NativeInputEventReceiver中的handleEvent()收到事件,将事件最后转为java层的InputEvent,然后抛出。
  2. Java层通过WindowInputEventReceiver接受事件,然后将事件添加到事件队列队尾,开启责任链调用模式
  3. Java层的inputEvent事件在责任链的ViewPostImeInputStage对象中处理,根据事件的类型,分发事件。
  4. 将MotionEvent事件通过发到View的根节点DecorView中,在根据Window回调,将事件发到Activity的dipatchTouchEvent()中,从此开始了touch事件的分发机制。

猜你喜欢

转载自blog.csdn.net/massonJ/article/details/107979983