Android home和back事件处理

来源:互联网 发布:管家婆成本算法怎么改 编辑:程序博客网 时间:2024/06/06 20:52

本文基于Android 7.0

在Android系统中,back键事件是有app自己处理的,而home是系统全局处理事件,因为在任何app界面,按下home结果都是一样的回到launcher。

先看下back事件

back键处理

Android事件处理过程大致为
  • Native层 –> ViewRootImpl层 –> DecorView层 –> Activity层 –> ViewGroup层 –> View层
从ViewRootImpl层开始看下back事件
frameworks/base/core/java/android/view/ViewRootImpl.javaprivate int processKeyEvent(QueuedInputEvent q) {            final KeyEvent event = (KeyEvent)q.mEvent;            // Deliver the key to the view hierarchy.            if (mView.dispatchKeyEvent(event)) {                return FINISH_HANDLED;            }            ...            return FORWARD;        }

这里的mView是DecorView,直接调用DecorView的dispatchKeyEvent分发事件
frameworks/base/core/java/com/android/internal/policy/DecorView.javapublic boolean dispatchKeyEvent(KeyEvent event) {       ...        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;            }        }        ...    }

分发back事件时mWindow还玩destroy,因此会调用Callback的dispatchKeyEvent分发,这里Callback为Activity。
frameworks/base/core/java/android/app/Activity.javapublic boolean dispatchKeyEvent(KeyEvent event) {        ...        return event.dispatch(this, decor != null                ? decor.getKeyDispatcherState() : null, this);    }
调用了KeyEvent的dispatch继续分发
frameworks/base/core/java/android/view/KeyEvent.javapublic 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;    }

主要看下ACTION_DOWN事件,这里receiver是activity。如果是长按,则会调用activity的onKeyLongPress
frameworks/base/core/java/android/app/Activity.javapublic boolean onKeyLongPress(int keyCode, KeyEvent event) {        return false;    }

可以看到直接返回false,忽略掉的长按事件
如果非长按,则会调用activity的onKeyDown
frameworks/base/core/java/android/app/Activity.java   public boolean onKeyDown(int keyCode, KeyEvent event)  {        if (keyCode == KeyEvent.KEYCODE_BACK) {            if (getApplicationInfo().targetSdkVersion                    >= Build.VERSION_CODES.ECLAIR) {                event.startTracking();            } else {                onBackPressed();            }            return true;        }       ...        }    }

可以看到按下back键会调用onBackPressed()方法,该方法最终会调用到finish()方法。
frameworks/base/core/java/android/app/Activity.java    public void onBackPressed() {        if (mActionBar != null && mActionBar.collapseActionView()) {            return;        }        if (!mFragments.getFragmentManager().popBackStackImmediate()) {            finishAfterTransition();        }    }  public void finishAfterTransition() {        if (!mActivityTransitionState.startExitBackTransition(this)) {            finish();        }    }

home事件

home事件是不经过app统一由系统处理的,在PhoneWindowManager端拦截掉了
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java// First we always handle the home key here, so applications        // can never break it, although if keyguard is on, we do let        // it handle it, because that gives us the correct 5 second        // timeout.public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {if (keyCode == KeyEvent.KEYCODE_HOME) {           ...            // If we have released the home key, and didn't do anything else            // while it was pressed, then it is time to go home!            if (!down) {                cancelPreloadRecentApps();                mHomePressed = false;                ...                handleShortPressOnHome();                return -1;            }...}

private void handleShortPressOnHome() {        // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.        getHdmiControl().turnOnTv();        // If there's a dream running then use home to escape the dream        // but don't actually go home.        if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {            mDreamManagerInternal.stopDream(false /*immediate*/);            return;        }        // Go home!        launchHomeFromHotKey();    }
launchHomeFromHotKey就回到launcher了。


0 0
原创粉丝点击