自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Key事件的分發(fā)邏輯,Android按鍵事件的產(chǎn)生與處理解析

移動(dòng)開發(fā) Android
KeyEvent類的dispatch方法實(shí)現(xiàn)了按鍵事件的分發(fā)和處理,為Android應(yīng)用程序提供了豐富的按鍵事件處理能力。
  1. 「事件的產(chǎn)生」:當(dāng)用戶按下物理按鍵、使用遙控器、輸入法或其他USB-OTG外接鍵盤等設(shè)備時(shí),會(huì)產(chǎn)生按鍵事件(KeyEvent)。
  2. 「事件的分發(fā)」:
  • 「分發(fā)起點(diǎn)」:按鍵事件由Android系統(tǒng)接收,通過(guò)Linux層分發(fā)到PhoneWindowManager(系統(tǒng)進(jìn)程)和ViewRootImpl(應(yīng)用進(jìn)程)。
  • 「分發(fā)順序」:PhoneWindowManager先執(zhí)行,處理系統(tǒng)級(jí)的按鍵事件(如音量鍵、電源鍵等),ViewRootImpl后執(zhí)行,處理應(yīng)用層的按鍵事件(如方向鍵、回車鍵等)。
  • 「分發(fā)過(guò)程」:在ViewRootImpl中,存在一個(gè)名為InputStage的責(zé)任鏈,用于處理輸入事件,每個(gè)階段都可能對(duì)事件進(jìn)行處理或?qū)⑵鋫鬟f給下一個(gè)階段。

/frameworks/base/core/java/android/view/ViewRootImpl.java

private int processKeyEvent(QueuedInputEvent q) {
    final KeyEvent event = (KeyEvent) q.mEvent;
    if (mUnhandledKeyManager.preViewDispatch(event)) {
        return FINISH_HANDLED;
    }

    // Deliver the key to the view hierarchy.
    if (mView.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }

    if (shouldDropInputEvent(q)) {
        return FINISH_NOT_HANDLED;
    }

    // This dispatch is for windows that don't have a Window.Callback. Otherwise,
    // the Window.Callback usually will have already called this (see
    // DecorView.superDispatchKeyEvent) leaving this call a no-op.
    if (mUnhandledKeyManager.dispatch(mView, event)) {
        return FINISH_HANDLED;
    }

    int groupNavigationDirection = 0;

    if (event.getAction() == KeyEvent.ACTION_DOWN
            && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
        if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
            groupNavigationDirection = View.FOCUS_FORWARD;
        } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
            groupNavigationDirection = View.FOCUS_BACKWARD;
        }
    }

    // If a modifier is held, try to interpret the key as a shortcut.
    if (event.getAction() == KeyEvent.ACTION_DOWN && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) && event.getRepeatCount() == 0
                    && !KeyEvent.isModifierKey(event.getKeyCode())
                    && groupNavigationDirection == 0) {
        if (mView.dispatchKeyShortcutEvent(event)) {
            return FINISH_HANDLED;
        }
        if (shouldDropInputEvent(q)) {
            return FINISH_NOT_HANDLED;
        }
    }

    // Apply the fallback event policy.
    if (mFallbackEventHandler.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }
    if (shouldDropInputEvent(q)) {
        return FINISH_NOT_HANDLED;
    }

    // Handle automatic focus changes.
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        if (groupNavigationDirection != 0) {
            if (performKeyboardGroupNavigation(groupNavigationDirection)) {
                return FINISH_HANDLED;
            }
        } else {
            if (performFocusNavigation(event)) {
                return FINISH_HANDLED;
            }
        }
    }
    return FORWARD;
}
  • 在處理按鍵事件之前,首先會(huì)調(diào)用mUnhandledKeyManager.preViewDispatch(event)來(lái)判斷是否有未處理的按鍵事件。如果有未處理的事件,則直接返回FINISH_HANDLED表示該事件已被處理。
  • 如果沒有未處理的事件,則調(diào)用mView.dispatchKeyEvent(event)將按鍵事件分發(fā)給View層次結(jié)構(gòu)。如果View層次結(jié)構(gòu)中的任何一個(gè)View處理了該事件,則直接返回FINISH_HANDLED表示該事件已被處理。
  • 如果按鍵事件不能被處理或應(yīng)該被丟棄,則調(diào)用shouldDropInputEvent(q)方法來(lái)決定是否應(yīng)該丟棄該事件。如果應(yīng)該丟棄,則返回FINISH_NOT_HANDLED表示該事件未被處理;否則繼續(xù)處理該事件。
  • 如果事件仍未被處理,則調(diào)用mUnhandledKeyManager.dispatch(mView, event)來(lái)判斷是否有未處理的事件。如果有,則直接返回FINISH_HANDLED表示該事件已被處理。
  • 如果按鍵事件是一個(gè)特定的按鍵(如Tab鍵)并且同時(shí)滿足一些特定的條件,則設(shè)置groupNavigationDirection變量并調(diào)用performKeyboardGroupNavigation方法來(lái)處理自動(dòng)的聚焦變化。
  • 如果按鍵事件是一個(gè)快捷鍵(即同時(shí)按下一個(gè)或多個(gè)修飾鍵和另一個(gè)鍵),則調(diào)用mView.dispatchKeyShortcutEvent(event)將事件分發(fā)給View層次結(jié)構(gòu)來(lái)嘗試解釋該按鍵事件。如果該事件被處理,則返回FINISH_HANDLED表示該事件已被處理。
  • 如果事件仍未被處理,則調(diào)用mFallbackEventHandler.dispatchKeyEvent(event)應(yīng)用回退事件策略來(lái)嘗試處理該事件。如果該事件被處理,則返回FINISH_HANDLED表示該事件已被處理。
  • 如果事件仍未被處理,則調(diào)用performFocusNavigation方法來(lái)處理自動(dòng)的聚焦變化。如果該事件被處理,則返回FINISH_HANDLED表示該事件已被處理。
  • 最后,如果事件仍未被處理,則返回FORWARD表示該事件應(yīng)該被傳遞給下一個(gè)事件處理程序。
private boolean performFocusNavigation(KeyEvent event) {
    int direction = 0;
    switch (event.getKeyCode()) {
        case KeyEvent.KEYCODE_DPAD_LEFT:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_LEFT;
            }
            break;
        case KeyEvent.KEYCODE_DPAD_RIGHT:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_RIGHT;
            }
            break;
        case KeyEvent.KEYCODE_DPAD_UP:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_UP;
            }
            break;
        case KeyEvent.KEYCODE_DPAD_DOWN:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_DOWN;
            }
            break;
        case KeyEvent.KEYCODE_TAB:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_FORWARD;
            } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
                direction = View.FOCUS_BACKWARD;
            }
            break;
    }
    if (direction != 0) {
        View focused = mView.findFocus();
        if (focused != null) {
            View v = focused.focusSearch(direction);
            if (v != null && v != focused) {
                // do the math the get the interesting rect
                // of previous focused into the coord system of
                // newly focused view
                focused.getFocusedRect(mTempRect);
                if (mView instanceof ViewGroup) {
                    ((ViewGroup) mView).offsetDescendantRectToMyCoords(focused, mTempRect);
                    ((ViewGroup) mView).offsetRectIntoDescendantCoords(v, mTempRect);
                }
                if (v.requestFocus(direction, mTempRect)) {
                    Log.i(TAG, "v.requestFocus == true");
                    boolean isFastScrolling = event.getRepeatCount() > 0;
                    playSoundEffect(SoundEffectConstants.getConstantForFocusDirection(direction,isFastScrolling));
                    return true;
                }
            }

            // Give the focused view a last chance to handle the dpad key.
            if (mView.dispatchUnhandledMove(focused, direction)) {
                return true;
            }
        } else {
            if (mView.restoreDefaultFocus()) {
                return true;
            }
        }
    }
    return false;
}

該方法用于處理焦點(diǎn)導(dǎo)航相關(guān)的按鍵事件,例如方向鍵和Tab鍵等。該方法接收一個(gè)KeyEvent對(duì)象作為參數(shù),根據(jù)不同的按鍵碼和修飾符,計(jì)算出焦點(diǎn)導(dǎo)航的方向,然后嘗試在View樹中找到新的焦點(diǎn),并將其設(shè)置為當(dāng)前焦點(diǎn)。如果找到新的焦點(diǎn)并成功設(shè)置為當(dāng)前焦點(diǎn),則播放焦點(diǎn)變化時(shí)的聲音效果,并返回true表示焦點(diǎn)變化事件已被處理。如果沒有找到新的焦點(diǎn),或者新的焦點(diǎn)不接受焦點(diǎn)設(shè)置請(qǐng)求,則返回false表示該事件未被處理。

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

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    final int keyCode = event.getKeyCode();
    final int action = event.getAction();
    final boolean isDown = action == KeyEvent.ACTION_DOWN;

    if (isDown && (event.getRepeatCount() == 0)) {
        // First handle chording of panel key: if a panel key is held
        // but not released, try to execute a shortcut in it.
        if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
            boolean handled = dispatchKeyShortcutEvent(event);
            if (handled) {
                return true;
            }
        }

        // If a panel is open, perform a shortcut on it without the
        // chorded panel key
        if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
            if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
                return true;
            }
        }
    }

    if (!mWindow.isDestroyed()) {
        final Window.Callback cb = mWindow.getCallback();
        final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event);
        if (handled) {
            return true;
        }
    }
    boolean result = isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event) : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
    return result;
}

該方法用于處理按鍵事件的分發(fā)和處理,該方法接收一個(gè)KeyEvent對(duì)象,并提取出鍵碼和事件類型。如果該事件為按下事件并且重復(fù)次數(shù)為0,則執(zhí)行以下操作:

  • 首先,處理面板按鍵的彈奏:如果面板按鍵已按下但未釋放,則嘗試在其中執(zhí)行一個(gè)快捷方式。如果已處理該快捷方式,則返回true表示事件已處理。
  • 然后,如果面板已經(jīng)打開,則在沒有面板按鍵的情況下執(zhí)行其上的快捷方式。如果已處理該快捷方式,則返回true表示事件已處理。
  • 如果事件仍未被處理,則檢查Window對(duì)象是否已被銷毀,如果沒有,則獲取Window.Callback對(duì)象并將事件分派給它。如果已處理該事件,則返回true表示事件已處理。
  • 最后,如果事件仍未被處理,則將其傳遞給Window對(duì)象進(jìn)行處理,并返回該事件是否為按下事件的結(jié)果。
public boolean superDispatchKeyEvent(KeyEvent event) {
    // Give priority to closing action modes if applicable.
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        final int action = event.getAction();
        // Back cancels action modes first.
        if (mPrimaryActionMode != null) {
            if (action == KeyEvent.ACTION_UP) {
                mPrimaryActionMode.finish();
            }
            return true;
        }
    }

    if (super.dispatchKeyEvent(event)) {
        return true;
    }
    boolean handle = (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
    return handle;
}

其作用是對(duì)KeyEvent事件進(jìn)行分發(fā)處理。該方法首先判斷事件是否為返回鍵,如果是則優(yōu)先處理當(dāng)前的操作模式,如果存在操作模式則先結(jié)束操作模式,否則將事件交由父類ViewGroup進(jìn)行處理。如果父類能夠處理該事件,則返回true,否則返回false,并將事件交由該DecorView 所對(duì)應(yīng)的ViewRootImpl實(shí)例進(jìn)行處理。

其中,getViewRootImpl()方法返回當(dāng)前DecorView所在的ViewRootImpl實(shí)例。如果該實(shí)例存在,則調(diào)用dispatchUnhandledKeyEvent(event)方法進(jìn)行處理,否則返回false。dispatchUnhandledKeyEvent(event)方法用于將該事件交由輸入法進(jìn)行處理。

  1. 「View的事件處理」:
  • 「ViewGroup與View」:在Android中,ViewGroup是View的容器,負(fù)責(zé)分發(fā)事件給其子View。如果ViewGroup的dispatchTouchEvent方法返回true,事件被消費(fèi),不會(huì)傳遞給其onTouchEvent方法或子View。如果返回false,調(diào)用父控件的onTouchEvent方法或繼續(xù)傳遞給子View。
  • 「事件攔截」:ViewGroup有一個(gè)onInterceptTouchEvent方法,可以在事件傳遞給子View之前進(jìn)行攔截。如果該方法返回true,則事件被攔截并在當(dāng)前ViewGroup的onTouchEvent方法中處理。
  • 「事件消費(fèi)」:無(wú)論是ViewGroup還是View,如果onTouchEvent方法返回true,表示事件被消費(fèi),不再傳遞給其他View或父控件。

/frameworks/base/core/java/android/app/Activity.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();
    boolean handler = event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this);
    return handler;
}

該方法用于分發(fā)鍵事件,當(dāng)用戶按下或釋放某個(gè)按鍵時(shí),該方法將被調(diào)用。

  • 首先,方法調(diào)用onUserInteraction(),用于通知Activity用戶正在與應(yīng)用程序交互。
  • 接著,方法檢查事件是否為菜單鍵事件,如果是,則首先檢查 ActionBar 是否存在,并且將事件傳遞給 ActionBar 的 onMenuKeyEvent() 方法進(jìn)行處理。如果 ActionBar 成功處理該事件,則直接返回 true,表示事件已被處理。
  • 如果事件不是菜單鍵事件或者ActionBar無(wú)法處理該事件,則將事件傳遞給窗口處理,并返回窗口處理結(jié)果。如果窗口處理了該事件,則直接返回true,表示事件已被處理。
  • 如果事件既不是菜單鍵事件,也無(wú)法被窗口處理,則將事件分發(fā)給DecorView(該Activity 的根View),并返回DecorView的dispatchKeyEvent()方法的處理結(jié)果。

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

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

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

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onKeyEvent(event, 1);
    }

    if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
        if (super.dispatchKeyEvent(event)) {
            Log.e("ViewRootImpl","super.dispatchKeyEvent(event)");
            return true;
        }
    } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) {
        if (mFocused.dispatchKeyEvent(event)) {
            Log.e("ViewRootImpl","Focused.dispatchKeyEvent(event)");
            return true;
        }
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
    }
    return false;
}

用于將按鍵事件分派到該ViewGroup及其子View。該方法首先通過(guò)檢查ViewGroup本身的狀態(tài)(是否擁有焦點(diǎn)且有邊界)來(lái)決定是否自己處理KeyEvent,如果ViewGroup本身滿足條件,則通過(guò)調(diào)用父類的dispatchKeyEvent方法處理事件,并返回true表示已處理。如果ViewGroup本身不滿足條件,則將KeyEvent分派到當(dāng)前擁有焦點(diǎn)的子View,如果該子View處理了事件,則返回true表示已處理。如果KeyEvent最終未被處理,則返回false表示未處理。此方法還包含一些調(diào)試代碼,用于確保事件派發(fā)的一致性。

/frameworks/base/core/java/android/view/View.java

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
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
        Log.e("ViewRootImpl","mOnKeyListener.onKey");
        return true;
    }

    if (event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)) {
        Log.e("ViewRootImpl","event.dispatch");
        return true;
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
    }
    return false;
}

該方法用于分派鍵盤事件到對(duì)應(yīng)的視圖,并根據(jù)事件的處理結(jié)果返回一個(gè)布爾值。方法的參數(shù)event表示一個(gè)鍵盤事件,該事件將被分派到相應(yīng)的視圖。方法中的第一步是調(diào)用mInputEventConsistencyVerifier.onKeyEvent(event, 0)方法來(lái)記錄鍵盤事件的一些基本信息,用于后續(xù)的事件一致性檢查。然后會(huì)首先調(diào)用視圖的OnKeyListener對(duì)象(如果有的話)的onKey 方法,如果該方法返回true,則表示該鍵盤事件被該監(jiān)聽器處理,方法返回true,否則該鍵盤事件被傳遞給了該視圖的dispatch方法。在這里調(diào)用了event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)方法,該方法會(huì)根據(jù)鍵盤事件的類型,將其分發(fā)給視圖的onKeyDown或onKeyUp方法進(jìn)行處理。如果該事件被處理了,則返回true,否則會(huì)調(diào)用mInputEventConsistencyVerifier.onUnhandledEvent(event, 0)方法記錄該事件未被處理的信息,并返回false表示該事件未被處理。

/frameworks/base/core/java/android/view/KeyEvent.java

public final boolean dispatch(Callback receiver, DispatcherState state, Object target) {
    switch (mAction) {
        case ACTION_DOWN: {
            mFlags &= ~FLAG_START_TRACKING;
            if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state + ": " + this);
            boolean res = receiver.onKeyDown(mKeyCode, this);
            if (state != null) {
                if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
                    if (DEBUG) Log.v(TAG, "  Start tracking!");
                    state.startTracking(this, target);
                } else if (isLongPress() && state.isTracking(this)) {
                    try {
                        if (receiver.onKeyLongPress(mKeyCode, this)) {
                            if (DEBUG) Log.v(TAG, "  Clear from long press!");
                            state.performedLongPress(this);
                            res = true;
                        }
                    } catch (AbstractMethodError e) {
                    }
                }
            }
            return res;
        }
        case ACTION_UP:
            if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state + ": " + this);
            if (state != null) {
                state.handleUpEvent(this);
            }
            return receiver.onKeyUp(mKeyCode, this);
        case ACTION_MULTIPLE:
            final int count = mRepeatCount;
            final int code = mKeyCode;
            if (receiver.onKeyMultiple(code, count, this)) {
                return true;
            }
            if (code != KeyEvent.KEYCODE_UNKNOWN) {
                mAction = ACTION_DOWN;
                mRepeatCount = 0;
                boolean handled = receiver.onKeyDown(code, this);
                if (handled) {
                    mAction = ACTION_UP;
                    receiver.onKeyUp(code, this);
                }
                mAction = ACTION_MULTIPLE;
                mRepeatCount = count;
                return handled;
            }
            return false;
    }
    return false;
}

KeyEvent事件分發(fā)的核心代碼,主要處理按鍵事件的分發(fā)。當(dāng)一個(gè)按鍵事件被分發(fā)到一個(gè)View時(shí),該View首先嘗試處理該事件。如果該View無(wú)法處理該事件,則事件將被分發(fā)給它的parent View或Activity,直到事件被處理或到達(dá)了View層級(jí)的最頂層。

  • 該方法根據(jù)KeyEvent的不同Action,分別進(jìn)行處理。如果Action是ACTION_DOWN,即按下按鍵的事件,首先會(huì)調(diào)用Callback接口的onKeyDown方法來(lái)處理該事件,并根據(jù)事件處理的結(jié)果進(jìn)行相應(yīng)的處理。如果返回true,表示事件被成功處理,并且設(shè)置了FLAG_START_TRACKING標(biāo)志位,則會(huì)調(diào)用DispatcherState的startTracking方法來(lái)開始追蹤該事件。如果事件是長(zhǎng)按事件,且當(dāng)前正在追蹤該事件,則會(huì)調(diào)用Callback接口的onKeyLongPress方法來(lái)處理長(zhǎng)按事件。
  • 如果Action是ACTION_UP,即松開按鍵的事件,會(huì)調(diào)用Callback接口的onKeyUp方法來(lái)處理該事件,并根據(jù)DispatcherState是否存在,調(diào)用DispatcherState的handleUpEvent方法來(lái)結(jié)束追蹤該事件。
  • 如果Action是ACTION_MULTIPLE,即按鍵事件包含多個(gè)重復(fù)事件,會(huì)調(diào)用Callback接口的onKeyMultiple方法來(lái)處理該事件,并根據(jù)KeyEvent的repeatCount和keyCode信息,依次調(diào)用Callback接口的onKeyDown和onKeyUp方法來(lái)處理每一個(gè)重復(fù)事件,最后返回處理結(jié)果。

總的來(lái)說(shuō),KeyEvent類的dispatch方法實(shí)現(xiàn)了按鍵事件的分發(fā)和處理,為Android應(yīng)用程序提供了豐富的按鍵事件處理能力。

  1. 「特殊情況」:
  • 「自定義處理」:可以通過(guò)重寫Activity、ViewGroup或View的dispatchKeyEvent、onInterceptTouchEvent、onTouchEvent等方法來(lái)自定義按鍵事件的處理邏輯。
  • 「外圍設(shè)備」:對(duì)于藍(lán)牙鍵盤、USB鍵盤等外圍設(shè)備,Android通過(guò)KeyEvent事件機(jī)制與它們進(jìn)行交互。開發(fā)者可以通過(guò)重寫dispatchKeyEvent方法來(lái)截獲和處理這些設(shè)備發(fā)送的事件。

Key事件的分發(fā)邏輯是一個(gè)復(fù)雜但有序的過(guò)程,涉及事件的產(chǎn)生、分發(fā)和View的事件處理等多個(gè)階段。通過(guò)理解這個(gè)過(guò)程,可以更好地控制Android應(yīng)用中按鍵事件的行為。

責(zé)任編輯:武曉燕 來(lái)源: 沐雨花飛蝶
相關(guān)推薦

2017-03-14 13:51:23

AndroidView事件分發(fā)和處理

2017-02-21 12:20:20

Android事件分發(fā)機(jī)制實(shí)例解析

2023-10-08 08:23:44

Android事件邏輯

2013-05-21 11:33:11

Android游戲開發(fā)按鍵中斷事件

2010-08-06 10:03:42

Flex事件

2016-12-08 10:19:18

Android事件分發(fā)機(jī)制

2013-04-22 15:40:00

Android開發(fā)觸摸事件與點(diǎn)擊事件區(qū)別

2010-08-06 10:24:56

Flex事件分發(fā)

2024-02-04 17:16:22

ReactVue前端

2021-08-11 14:29:20

鴻蒙HarmonyOS應(yīng)用

2010-08-09 11:14:36

Flex事件處理

2013-05-14 11:08:23

AIR Android觸摸事件鼠標(biāo)事件

2012-12-28 14:53:34

Android開發(fā)初始化窗體事件

2023-03-14 07:31:17

EoscGo語(yǔ)言

2023-04-03 08:39:33

中間件go語(yǔ)言

2012-05-07 09:10:30

Android SDK交互體驗(yàn)功能按鍵事件

2021-08-03 06:57:36

Js事件節(jié)流

2024-06-25 08:43:25

C#編程模型

2013-04-24 11:15:56

Android開發(fā)Touch事件傳遞機(jī)制

2023-11-01 07:55:03

事件監(jiān)聽器傳遞數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)