从硬件的角度看,事件主要分为以下几类:
1,按键事件(KeyEvent)
2,触摸事件(TounchEvent)
3,鼠标事件(MouseEvent)
4,轨迹球事件(TrackballEvent)
底层通过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);
}
}
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;
结构图如下,
这个链表的开头要么是NativePreImeInputStage对象,要么是EarlyPostImeInputStage对象,
deliverInputEvent方法中会调用shouldSkipIme方法判断输入消息是否跳过给输入法框架处理(是否正在调用输入法),如果跳过,则从mFirstPostImeInputStage指向的EarlyPostImeInputStage对象开始处理,如果不跳过,则从mFirstInputStage NativePreImeInputStage开始处理。
从NativePreImeInputStage处理流程如下,首先调用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方法结束。
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:流水线的最后一级,经过层层过滤之后,到达这里的消息已经不多了,例如手机上的虚拟按键消息。
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根据事件的类型对事件进行处理。平时开发中使用最多的是按键事件和触摸事件,所以本文主要分析这两个事件。
下一篇文章主要论述按键事件的分发处理流程。
下下篇文章主要论述触摸事件的分发处理流程。