Android 从问题出发探索KeyEvent分发流程(3) View的keyListener是如何收到事件的

42 阅读1分钟

# Android 从问题出发探索KeyEvent分发流程(1) PhoneWindowManager是如何收到事件的

# Android 从问题出发探索KeyEvent分发流程(2) Activity是如何收到事件的

View的KeyListener相对于前两个过程要简单的多,不涉及那么多jni调用,我们继续跟随Activity收到KeyEvent向前走

Step 1 Activty调用window.superDispatchKeyEvent,将事件交给window(实现类PhoneWindow)

/base/core/java/com/android/internal/policy/PhoneWindow.java

public boolean dispatchKeyEvent(KeyEvent event) {
    onUserInteraction();

    // Let action bars open menus in response to the menu key prioritized over
    // the window handling it
    final int keyCode = event.getKeyCode();
    if (keyCode == KeyEvent.KEYCODE_MENU &&
            mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
        return true;
    }

    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);
}

Step 2 PhoneWindow转发Decoriew,一路将事件交给View处理

/base/core/java/com/android/internal/policy/PhoneWindow.java

public boolean superDispatchKeyEvent(KeyEvent event) {
    return mDecor.superDispatchKeyEvent(event);
}

/base/core/java/com/android/internal/policy/DecorView.java

public boolean superDispatchKeyEvent(KeyEvent event) {
    if (super.dispatchKeyEvent(event)) {
        return true;
    }

    return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
}

/base/core/java/android/view/ViewGroup.java

public boolean dispatchKeyEvent(KeyEvent event) {
    if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
            == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
        if (super.dispatchKeyEvent(event)) {
            return true;
        }
    } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
            == PFLAG_HAS_BOUNDS) {
        /// M : add log to help debugging
        if (ViewDebugManager.DEBUG_KEY) {
                Log.d(TAG, "dispatchKeyEvent to focus child event = " + event + ", mFocused = "
                + mFocused + ",this = " + this);
        }
        if (mFocused.dispatchKeyEvent(event)) {
            return true;
        }
    }
    return false;
}

Step 3 View校验keyListener是否为空和是否是enable状态,回调keyListener.onKey

public boolean dispatchKeyEvent(KeyEvent event) {
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
            && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
        /// M : add log to help debugging
        if (ViewDebugManager.DEBUG_KEY) {
            ViewDebugManager.getInstance().debugEventHandled(this, event, li.toString());
        }
        return true;
    }
    return false;
}

从Activity到View的KeyListener被调用,这个过程到这里就结束了