转载自
http://venus585625.iteye.com/blog/907740
写的不错,比较深入,转贴于此
在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;
- d 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();
- }