消息处理管道

时间:2021-09-25 05:34:43

TODO: 待写

消息处理管道

一个App看作是系统,外部输入消息需要经过一系列处理,涉及不同接收者。消息处理的跟踪(Trace)和结果的保存。
比如设计一个用来接收服务器推送消息的处理框架?

以Android中处理InputEvent的设计作为借鉴。

案例

android.view.ViewRootImpl.deliverInputEvent()分发消息
InputStage处理阶段

使用了什么模式?
解决了哪些问题?
什么时候使用?

处理的阶段:InputStage

InputStage mFirstInputStage;

private void deliverInputEvent(QueuedInputEvent q) {
try {

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

/**
* Base class for implementing a stage in the chain of responsibility
* for processing input events.
* <p>
* Events are delivered to the stage by the {@link #deliver} method. The stage
* then has the choice of finishing the event or forwarding it to the next stage.
* </p>
*/
abstract class InputStage {
private final InputStage mNext;

protected static final int FORWARD = 0;
protected static final int FINISH_HANDLED = 1;
protected static final int FINISH_NOT_HANDLED = 2;

/**
* Creates an input stage.
* @param next The next stage to which events should be forwarded.
*/
public InputStage(InputStage next) {
mNext = next;
}

/**
* Delivers an event to be processed.
*/
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
apply(q, onProcess(q));
}
}

/**
* Marks the the input event as finished then forwards it to the next stage.
*/
protected void finish(QueuedInputEvent q, boolean handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
if (handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
}
forward(q);
}

/**
* Forwards the event to the next stage.
*/
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}

/**
* Applies a result code from {@link #onProcess} to the specified event.
*/
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);
}
}

/**
* Called when an event is ready to be processed.
* @return A result code indicating how the event was handled.
*/
protected int onProcess(QueuedInputEvent q) {
return FORWARD;
}

/**
* Called when an event is being delivered to the next stage.
*/
protected void onDeliverToNext(QueuedInputEvent q) {
if (mNext != null) {
mNext.deliver(q);
} else {
finishInputEvent(q);
}
}

protected boolean shouldDropInputEvent(QueuedInputEvent q) {
if (mView == null || !mAdded) {
Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
return true;
} else if (!mAttachInfo.mHasWindowFocus &&
!q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
!isTerminalInputEvent(q.mEvent)) {
// If this is a focused event and the window doesn't currently have input focus,
// then drop this event. This could be an event that came back from the previous
// stage but the window has lost focus in the meantime.
Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
return true;
}
return false;
}
...
}