一個App看做是系統,外部輸入消息須要通過一系列處理,涉及不一樣接收者。消息處理的跟蹤(Trace)和結果的保存。
好比設計一個用來接收服務器推送消息的處理框架?java
以Android中處理InputEvent的設計做爲借鑑。android
android.view.ViewRootImpl.deliverInputEvent()分發消息
InputStage處理階段服務器
使用了什麼模式?
解決了哪些問題?
何時使用?app
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; } ... }