按键事件在activity中的流程
2015-07-23 10:37
281 查看
android的事件有很多种,touch、key、mouse等。但是基本流程大概是一致的。本文将探寻activity中的事件流程,至于事件如何传递到activity,将另起篇幅介绍。
activity的事件入口
以上代码是activity的dispatchKeyEvent()方法,该方法就是key事件的入口。至于其它的touch、mouse等事件,也都有类似的dispatch方法作为一类事件的入口。activity收到事件之后,会获取当前的window,将该事件传递给window。如果window的superDispatchKeyEvent()方法捕获该事件,则该事件传递结束。否则,将调用KeyEvent的dispatch()方法。
window的处理流程
Window接口的superDispatchKeyEvent()的api说明,已经明确指出,事件会通过此方法进入view层级中。其具体实现是在PhoneWindow中。
这个mDecor是PhoneWindow的一个内部类,直接继承于FrameLayout。
DecorView会按FrameLayout的方式处理该事件,此时,事件正式传递到了view层级中。如果FrameLayout未捕获该事件,并且是BACK按键时,DecorView会和ActionMode和ActionBar有简单交互。否则直接返回false。
View层级的事件处理
事件在View层级中传递,主要流程在ViewGroup和View中。先看ViewGroup的dispatchKeyEvent:
如果ViewGroup自身已经获得焦点,则调用View的dispatchKeyEvent();否则将查找焦点子View,将事件传递给焦点子View处理。
再看View的dispatchKeyEvent()
如果View设置了KeyListener,并且是enable状态,则该事件先由KeyListener处理。KeyListener返回true,则事件结束。否则调用KeyEvent的dispatch()方法。这个dispatch()方法的第一个参数是KeyEvent.Callback,它有2个方法onKeyDown()和onKeyUp()。View和Activity都实现了这个接口。dispatch方法将判断按键是up还是down,然后传递分发给callback。View在onKeyDown()和onKeyUp()中,主要处理了enter按键,设置和取消了press状态,触发click事件,并在一定条件下,触发long press状态。如果在Callback中返回true,则事件结束;否则,事件流程回溯到起点activity的dispatchKeyEvent()中的第二部分。即调用的KeyEvent的dispatch()方法,事件将进入activity的onKeyDown()和onKeyUp()中。这2个函数是在应用中可以接收到事件的最后机会。
事件流程总结
activity中先在dispatch函数中接收到事件,交由window处理,window则再转给DecorView,进入view层级处理。View层级中直接将事件转发给当前焦点view处理,而焦点view则依次转给自己的OnKeyListener回调、onKeyDown、onKeyUp处理。如果焦点view未处理,则回到了activity的dispatch函数,进入第二步流程onKeyDown、onKeyUp处理。这中间的节点是应用开发可以控制到的。至于事件如何进入activity、ime和activity如何事件交互,且看后续文章。
activity的事件入口
public boolean dispatchKeyEvent(KeyEvent event) { onUserInteraction(); 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); }
以上代码是activity的dispatchKeyEvent()方法,该方法就是key事件的入口。至于其它的touch、mouse等事件,也都有类似的dispatch方法作为一类事件的入口。activity收到事件之后,会获取当前的window,将该事件传递给window。如果window的superDispatchKeyEvent()方法捕获该事件,则该事件传递结束。否则,将调用KeyEvent的dispatch()方法。
window的处理流程
/** * Used by custom windows, such as Dialog, to pass the key press event * further down the view hierarchy. Application developers should * not need to implement or call this. * */ public abstract boolean superDispatchKeyEvent(KeyEvent event);
Window接口的superDispatchKeyEvent()的api说明,已经明确指出,事件会通过此方法进入view层级中。其具体实现是在PhoneWindow中。
@Override public boolean superDispatchKeyEvent(KeyEvent event) { return mDecor.superDispatchKeyEvent(event); }
这个mDecor是PhoneWindow的一个内部类,直接继承于FrameLayout。
public boolean superDispatchKeyEvent(KeyEvent event) { if (super.dispatchKeyEvent(event)) { return true; } // Not handled by the view hierarchy, does the action bar want it // to cancel out of something special? if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { // Back cancels action modes first. // ... return true; // Next collapse any expanded action views. // ... return true; } return false; }
DecorView会按FrameLayout的方式处理该事件,此时,事件正式传递到了view层级中。如果FrameLayout未捕获该事件,并且是BACK按键时,DecorView会和ActionMode和ActionBar有简单交互。否则直接返回false。
View层级的事件处理
事件在View层级中传递,主要流程在ViewGroup和View中。先看ViewGroup的dispatchKeyEvent:
public boolean dispatchKeyEvent(KeyEvent event) { // mInputEventConsistencyVerifier.onKeyEvent(event, 1); if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { if (super.dispatchKeyEvent(event)) { return true; } } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { if (mFocused.dispatchKeyEvent(event)) { return true; } } // mInputEventConsistencyVerifier.onUnhandledEvent(event, 1); return false; }
如果ViewGroup自身已经获得焦点,则调用View的dispatchKeyEvent();否则将查找焦点子View,将事件传递给焦点子View处理。
再看View的dispatchKeyEvent()
public boolean dispatchKeyEvent(KeyEvent event) { // 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)) { return true; } if (event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)) { return true; } // mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); return false; }
如果View设置了KeyListener,并且是enable状态,则该事件先由KeyListener处理。KeyListener返回true,则事件结束。否则调用KeyEvent的dispatch()方法。这个dispatch()方法的第一个参数是KeyEvent.Callback,它有2个方法onKeyDown()和onKeyUp()。View和Activity都实现了这个接口。dispatch方法将判断按键是up还是down,然后传递分发给callback。View在onKeyDown()和onKeyUp()中,主要处理了enter按键,设置和取消了press状态,触发click事件,并在一定条件下,触发long press状态。如果在Callback中返回true,则事件结束;否则,事件流程回溯到起点activity的dispatchKeyEvent()中的第二部分。即调用的KeyEvent的dispatch()方法,事件将进入activity的onKeyDown()和onKeyUp()中。这2个函数是在应用中可以接收到事件的最后机会。
事件流程总结
activity中先在dispatch函数中接收到事件,交由window处理,window则再转给DecorView,进入view层级处理。View层级中直接将事件转发给当前焦点view处理,而焦点view则依次转给自己的OnKeyListener回调、onKeyDown、onKeyUp处理。如果焦点view未处理,则回到了activity的dispatch函数,进入第二步流程onKeyDown、onKeyUp处理。这中间的节点是应用开发可以控制到的。至于事件如何进入activity、ime和activity如何事件交互,且看后续文章。
相关文章推荐
- #ifdef DEBUG的理解
- SQLIO 磁盘测试工具参考
- 最全面的前端面试问题及答案总结
- HTML如何让文本两端对齐
- [geeksforgeeks] Count the number of occurrences in a sorted array
- [树状数组] poj3468 A Simple Problem with Integers
- 暑假集训第二周——贪心 G - Game Prediction游戏预测
- service心得
- 行列互转
- swift 判断当前设备网络是否可用
- Activity的四种加载模式
- hive数据倾斜
- Div+CSS+JQuery轻松实现选项卡"选项卡"
- 同一个数据库实例,不同用户下多表创建视图,Hibernate完成ORM映射,Spring整合,后台实现
- ZZUOJ - 1195 - OS Job Scheduling
- iOS静态代码分析时常见错误及解决办法
- CSocketServer.cpp
- maven笔记一
- CGI
- iOS 7 隐藏特性