android事件分发

先参考一下老罗同志的关于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(输入法)处理之前
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将不会被调用了。






  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值