1. 在Activity的启动过程中,窗口和视图创建完后, 会创建输入通道InPutChannel, 该类执行了Parceladble,专门用来传输用户输入事件给window.
2. 用InPutChannel和主线程的Looper作为参数创建事件接收器WindowInputEventReceiver.
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
WindowInputEventReceiver继承InputEventReceiver,是ViewRootImpl的内部类.
3. 当native层的输入管理器监听到输入事件后调用InputEventReceiver.dispatchInputEvent()方法,该方法再通过以下调用链最终进入DecorView.dispatchKeyEvent()方法执行.
WindowInputEventReceiver.onInputEvent()—>enqueueInputEvent()—>doProcessInputEvents()—>deliverInputEvent()—>deliver()—>
ViewPostImeInputStage.onProcess()—>ViewPostImeInputStage.processKeyEvent()—>DecorView.dispatchKeyEvent()
4. DecorView.dispatchKeyEvent()方法有两个分支:
1) 在窗口被销毁的时候,比如息屏状态下调整音量,则直接调用PhoneWindow.onKeyDown()方法,并在该方法中处理音量的调节.
2) 在窗口没有被销毁的时候,调用Activity.dispatchKeyEvent()方法进行事件分发.
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
final int action = event.getAction();
final boolean isDown = action == KeyEvent.ACTION_DOWN;
...
if (!isDestroyed()) { //窗口没有销毁的情况
final Callback cb = getCallback();
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) //这个Callback是在activity的attach()方法里面设置到window中的。
: super.dispatchKeyEvent(event);
if (handled) {
return true;
}
}
return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event) //窗口销毁后直接调用PhoneWindow的onkeyDown()方法处理。
: PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
5. Activity通过PhoneWindow将事件传递给view系统
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 && //按的menu键,则直接调用mActionBar.onMenuKeyEvent(event),并返回true,事件不再向下传递。
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
}
Window win = getWindow();
if (win.superDispatchKeyEvent(event)) { //通过PhoneWindow调用view和viewgrounp的Dispatch方法传递事件,如果该事件被某个view或者viewgrounp处理,
// 返回true,到此结束,否则继续向下传递。
return true;
}
View decor = mDecor;
if (decor == null) decor = win.getDecorView();
return event.dispatch(this, decor != null
? decor.getKeyDispatcherState() : null, this); //如果该事件没有被view或者viewgrounp处理,则直接调用event.dispatch(),
//在该方法里面调用activiy的onkeydown()方法处理。
}
6. view系统将事件从根view开始向子view传递,如果事件被某个view或者viewGrounp消费,则停止向下传递,否则最终将调用Activity的onKeyDown()方法进行处理.
以textView为例,事件在view系统的传递路径为:
DecorView.superDispatchKeyEvent()—>viewgrounp.dispatchKeyEvent()—>view.dispatchKeyEvent()—>KeyEvent.dispatch()—>TextView.onKeyDown()