android事件分發

來源:互聯網
上載者:User

先參考一下老羅同志的關於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將不會被調用了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.