在android中,所有的按键、触屏等事件,都是从顶至下进行分发的。每个ViewGroup子类对象会维持一个Focused变量。它表示在这个控件中具有Focused控件(此控件或是其子控件)。当有按键发生时 会沿着Focuse Path 找到RealFocus 控件(是真正Focused 控件,不是其子控件具有焦点)。同理触屏事件的分发也是如此,只不过和Focuse无关。父控件会遍历所有子控件,看看谁处于触碰事件,并分发给它。
如果Home key、Menu key,Back Key,Enter key事件(或许还有别的按键)(一些特殊功能的按键,声音等等)发生时 ,会产生一个FINISHED_EVENT 消息,是由InPutMethodManagerService通过AIDL进程调用产生 。
在ViewRoot 中捕获。
case FINISHED_EVENT:
handleFinishedEvent(msg.arg1, msg.arg2 != 0);
break;
void handleFinishedEvent(int seq, boolean handled) {
final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
+ " handled=" + handled + " event=" + event);
if (event != null) {
final boolean sendDone = seq >= 0;
if (!handled) {
deliverKeyEventToViewHierarchy(event, sendDone);
return;
} else if (sendDone) {
if (LOCAL_LOGV) Log.v(
"ViewRoot", "Telling window manager key is finished");
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
}
} else {
Log.w("ViewRoot", "handleFinishedEvent(seq=" + seq
+ " handled=" + handled + " ev=" + event
+ ") neither delivering nor finishing key");
}
}
}
普通按键 发生时,产生DISPATCH_KEY_FROM_IME 消息 由ViewRoot捕获此消息
case DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
"ViewRoot", "Dispatching key "
+ msg.obj + " from IME to " + mView);
KeyEvent event = (KeyEvent)msg.obj;
if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
// The IME is trying to say this event is from the
// system! Bad bad bad!
event = KeyEvent.changeFlags(event,
event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
}
deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
} break;
上面两大类按键如果预先没有别处理,都会由deliverKeyEventToViewHierarchy(event, sendDone);进行分发。
分发路径:PhoneWindow.DecorView dispatchKeyEvent----》Activity dispatchKeyEvent ----》Window superDispatchKeyEvent --->DecorView superDispatchKeyEvent-->Super dispatchKeyEvent,后续按着 Focus Path分发。如果上述分发中未被处理
会执行Activity dispatchKeyEvent 中的如下代码:
event.dispatch(this, decor != null
? decor.getKeyDispatcherState() : null, this);
进一步调用Focus Path中的 View 的 onXXX方法。如果在这些回调方法中,按键未被处理,则进一步由 PhoneWindow.DecorView中dispatchKeyEvent方法的代码
return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
: PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
处理了:volumn key ,back key 等等按键。
了解了这些就可以游刃有余地截获按键事件。。
“Home key”如果应用程序中没有截获,则最后调用 Activity 中的onBackPressed
默认实现:
/**
* Called when the activity has detected the user's press of the back
* key. The default implementation simply finishes the current activity,
* but you can override this to do whatever you want.
*/
public void onBackPressed() {
finish();
}