应用层分发事件分析(七)

1 概念

从硬件的角度看,事件主要分为以下几类:

1,按键事件(KeyEvent)

2,触摸事件(TounchEvent)

3,鼠标事件(MouseEvent)

4,轨迹球事件(TrackballEvent)

2 ViewRootImpl事件处理

底层通过JNI会调用ViewRootImpl内部类WindowInputEventReceiver的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);

   if (processImmediately) { // 是否立即处理消息
            doProcessInputEvents();
    } else {
      scheduleProcessInputEvents(); // 发送handler消息,最终也会调用doProcessInputEvents方法
   }
 }

doProcessInputEvents会调用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);
        }
    }

2.1 InputStage

ViewRootImpl的setView方法最后一段代码如下,

CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;

构造了7个类,并且这7个类都是InputStage的子类,

首先看ViewPostImeInputStage的构造方法,

public ViewPostImeInputStage(InputStage next) {
            super(next);
        }

InputStage的构造方法如下,

public InputStage(InputStage next) {
            mNext = next;
        }

mNext是InputStage的一个变量,有点类似于一个单向链表,

private final InputStage mNext;

结构图如下,

应用层分发事件分析(七)_第1张图片

这个链表的开头要么是NativePreImeInputStage对象,要么是EarlyPostImeInputStage对象,

2.2 流水线处理

deliverInputEvent方法中会调用shouldSkipIme方法判断输入消息是否跳过给输入法框架处理(是否正在调用输入法),如果跳过,则从mFirstPostImeInputStage指向的EarlyPostImeInputStage对象开始处理,如果不跳过,则从mFirstInputStage NativePreImeInputStage开始处理。

从NativePreImeInputStage处理流程如下,

应用层分发事件分析(七)_第2张图片

首先调用deliver方法,父类InputStage的deliver方法如下, 

public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q); // 分发给下一个InputStage对象来处理
            } else if (shouldDropInputEvent(q)) { // 是否需要丢弃
                finish(q, false);
            } else {
                apply(q, onProcess(q));
            }
        }

forward方法调用的流程如下,

protected void onDeliverToNext(QueuedInputEvent q) {
            if (DEBUG_INPUT_STAGES) {
                Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
            }
            if (mNext != null) {
                mNext.deliver(q); // 调用下一级来进行处理
            } else {
                finishInputEvent(q); // 如果是最后一级,直接finish
            }
        }

Finish方法如下,

protected void finish(QueuedInputEvent q, boolean handled) {
            q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
            if (handled) {
                q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
            }
            forward(q);
        }

Finish方法会给这个消息加上FLAG_FINISHED标志,这样后面的InputStage对象也不会处理了,一直到流水线的结尾。

最后的apply方法如下,

protected void apply(QueuedInputEvent q, int result) {
            if (result == FORWARD) {
                forward(q);
            } else if (result == FINISH_HANDLED) {
                finish(q, true);
            } else if (result == FINISH_NOT_HANDLED) {
                finish(q, false);
            } else {
                throw new IllegalArgumentException("Invalid result: " + result);
            }
        }

Result参数是调用onprocess的结果,如果结果是FORWARD(本InputStage对象未处理),则调用forward方法给下一个InputStage对象处理;如果结果是FINISH_HANDLED(本InputStage对象已处理),直接finish; ,如果结果是FINISH_NOT_HANDLED(消息虽然没有处理,但是要结束),则调用finish方法结束。

2.3 InputStage作用

1,NativePreImeInputStage:主要是为了将消息放到NativeActivity中去处理, NativeActivity和普通acitivty的功能区别不大,只是很多代码都在native层去实现,这样执行效率更高,并且NativeActivity在游戏开发中很实用。

2, ViewPreImeInputStage:从名字中就可得知,最后会调用acitivity的所有view的onkeyPreIme方法,这样就给View在输入法处理key事件之前先得到消息并处理的机会。

3, ImeInputStage: ImeInputStage的onProcess方法会调用InputMethodManager的dispatchInputEvent方法处理消息。

4, EarlyPostImeInputStage:屏幕上有焦点的View会高亮显示,用来提示用户焦点所在。

5, NativePostImeInputStage:为了让IME处理完消息后能先于普通的Activity处理消息。

6, ViewPostImeInputStage:acitivity和view处理各种消息。

7, SyntheticInputStage:流水线的最后一级,经过层层过滤之后,到达这里的消息已经不多了,例如手机上的虚拟按键消息。

2.4 onProcess

ViewPostImeInputStage的onProcess方法如下,

protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q); // 处理key事件
            } else {
                // If delivering a new non-key event, make sure the window is
                // now allowed to start updating.
                handleDispatchWindowAnimationStopped();
                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); // 处理其他事件
                }
            }
        }

onProcess根据事件的类型对事件进行处理。平时开发中使用最多的是按键事件和触摸事件,所以本文主要分析这两个事件。

下一篇文章主要论述按键事件的分发处理流程。

下下篇文章主要论述触摸事件的分发处理流程。

你可能感兴趣的:(---【消息处理分析】,应用层消息分发,InputStage,android)