先參考一下老羅同志的關於key事件的分發流程。http://blog.csdn.net/luoshengyang/article/details/6882903#comments
這裡主要是寫一下事件從native層上到Java層後,即到了InputQueue後的分發流程,以keyEvent為例。
InputQueue.java中
private static void dispatchKeyEvent(InputHandler inputHandler, KeyEvent event, long finishedToken) { FinishedCallback finishedCallback = FinishedCallback.obtain(finishedToken); inputHandler.handleKey(event, finishedCallback); }
這是從native層回調java層的,接著調用了Inputhander的handlKey。InputHandler是一個介面,主要是ViewRootImpl的mInputHandler變數實現了這個介面。
private final InputHandler mInputHandler = new InputHandler() { public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); dispatchKey(event, true); }
然後dispatchKey通過訊息機制,會調用deliverKeyEvent()處理。在此函數中,會分幾部,IME(IME)處理之前
dispatchKeyEventPreIme
,ime處理,ime處理之後的處理
deliverKeyEventPostIme
// Perform predispatching before the IME. if (mView.dispatchKeyEventPreIme(event)) { finishKeyEvent(event, sendDone, true); return; } // Dispatch to the IME before propagating down the view hierarchy. // The IME will eventually call back into handleFinishedEvent. if (mLastWasImTarget) { InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) { int seq = enqueuePendingEvent(event, sendDone); if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq=" + seq + " event=" + event); imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback); return; } } // Not dispatching to IME, continue with post IME actions. deliverKeyEventPostIme(event, sendDone);
此處會有一個mView,是View類型,其實是Decorview。如何看出它是Decorview?可以看出,mView是在setView被賦的值,setview會在WindowManagerImpl的addview中調用,並傳入了view參數。WindowManagerImpl也即是WindowManager的一個實現。addView則是由PhoneWindowmanager的addStartingWindow函數的wm.addView調用的,將DecorView傳入。
那誰又會調用addStartingWindow?看名字吧,簡單縷一下調用關係: ActivityStack-->WMS.setAppStartingWindow-->policy.addStartingWindow-->PhoneWindowManager.addStartingWindow-->WindowManager(impl).addview-->ViewRootImpl.setview.
一般來說,會執行deliverKeyEventPostIme。
// Make sure the fallback event policy sees all keys that will be delivered to the // view hierarchy. mFallbackEventHandler.preDispatchKeyEvent(event); // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) { finishKeyEvent(event, sendDone, true); return; }
mFallbackEventHandler ,其實是PhoneFallbackEventHandler類型。
事件會分發到DecorView的dispatchKeyEvent。
DecorView(PhoneWindow的內部類):
if (!isDestroyed()) { final Callback cb = getCallback(); final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event); if (handled) { return true; } }
mFeatureId為-1,所以會通過cb.dispatchkeyEvent。通過查看代碼會發現,cb是Window的Callback介面,由activity和dialog實現。就以activity為例吧,即分發到Activity的dispatchKeyEvent。
public boolean dispatchKeyEvent(KeyEvent event) { onUserInteraction(); Window win = getWindow(); if (win.superDispatchKeyEvent(event)) { return true; } View decor = mDecor; if (decor == null) decor = win.getDecorView(); return event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this); }
從activity出發,先分發到視窗Window(phonewindow),然後沒有被消耗掉的話再去調用activity的KeyEvent.dispatch, 回調onKeyDown。
PhoneWindow:
public boolean superDispatchKeyEvent(KeyEvent event) { return mDecor.superDispatchKeyEvent(event); }
調用了DecorView的superDispatchKeyEvent
public boolean superDispatchKeyEvent(KeyEvent event) { if (super.dispatchKeyEvent(event)) { return true; } // Not handled by the view hierarchy, does the action bar want it // to cancel out of something special? if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { final int action = event.getAction(); // Back cancels action modes first. if (mActionMode != null) { if (action == KeyEvent.ACTION_UP) { mActionMode.finish(); } return true; }
先分發到父類的dispatchKeyEvent。即FrameLayout-->ViewGroup
public boolean dispatchKeyEvent(KeyEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onKeyEvent(event, 1); } if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { if (super.dispatchKeyEvent(event)) { return true; } } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { if (mFocused.dispatchKeyEvent(event)) { return true; } }
同樣也是,看看焦點問題,會調用super也就是View的dispatchKeyEvent。
public boolean dispatchKeyEvent(KeyEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onKeyEvent(event, 0); } // Give any attached key listener a first crack at the event. //noinspection SimplifiableIfStatement if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnKeyListener.onKey(this, event.getKeyCode(), event)) { return true; } if (event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)) { return true; }
調用event.dispatch時,如果down事件,則執行boolean res = receiver.onKeyDown(mKeyCode, this);此處是View調用,所以就回調View的onKeyDown。如果是activity調用,則執行activity的onKeyDown.
如果在這分發的過程中,返回了true,則相當於事件被消費掉了,則activity的onKeydown將不會被調用了。