Android Activity的按键事件处理流程

       Android里,Activity按键事件相关的分发/处理函数有如下几个:

       1) public boolean dispatchKeyEvent(KeyEvent event);

      2)public boolean onKeyDown(int keyCode, KeyEvent event);

      3)public void onBackPressed(); //back键的处理函数

     app开发者一般会override这几个函数来做一些自定义处理,那么这几个函数的调用关系以及执行的先后顺序是怎么样的呢? 今天抽时间看了一下Activity类的源码,总算理清了一些头绪,赶紧写下来记录已经跟大家share一下~!

     首先说明一下这3个函数的执行顺序就是我上面列出来的顺序。具体每个函数是如何调用到的,下面我们通过源码来做一下解释和说明。假设用户在某个Activity A上按了back键, 那么肯定是A的dispatchKeyEvent()方法先被调用到, 这个函数的源码如下:   

/**
 * Called to process key events.  You can override this to intercept all
 * key events before they are dispatched to the window.  Be sure to call
 * this implementation for key events that should be handled normally.
 *
 * @param event The key event.
 *
 * @return boolean Return true if this event was consumed.
 */
public boolean dispatchKeyEvent(KeyEvent event) {
    onUserInteraction();

    // Let action bars open menus in response to the menu key prioritized over
    // the window handling it
    if (event.getKeyCode() == 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);
}
     我们看到,menu键会在分发到A所在的window前被actionbar优先处理, window分发/处理按键的函数是superDispatchKeyEvent(), 这个函数是个abstract函数,需要结合具体的window实现源码来分析(Activity的window貌似是一个叫PhoneWindow的类)。 最关键的是要看event的dispatch()函数了,这个函数的第一个参数Receiver是Callback接口类型,  这里传入的是this,也即当前的Activity。 这个函数里会根据Action的值来执行Activity的onKeyDown()/onKeyUp()/onKeyMultiple()函数。 KeyEvent.dispatch()函数的源码如下:

 

/**
 * Deliver this key event to a {@link Callback} interface.  If this is
 * an ACTION_MULTIPLE event and it is not handled, then an attempt will
 * be made to deliver a single normal event.
 *
 * @param receiver The Callback that will be given the event.
 * @param state State information retained across events.
 * @param target The target of the dispatch, for use in tracking.
 *
 * @return The return value from the Callback method that was called.
 */
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);  //调用Activity的onKeyDown()
            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); //调用Activity的onKeyUp()函数
        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;
}

       我们再来看一下Activity的onKeydown()函数里都干了些什么? 对于back键来说, 在Android 2.0以前,会直接调用onBackPressed()函数;在Android 2.0之后,会调用event.startTracking(), 至于onBackPressed()函数,是在onKeyUp()里调用的:

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

public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (getApplicationInfo().targetSdkVersion
            >= Build.VERSION_CODES.ECLAIR) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
                && !event.isCanceled()) {
            onBackPressed();
            return true;
        }
    }
    return false;
}


   

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值