Android事件传递

来源:互联网 发布:淘宝网开店流程 编辑:程序博客网 时间:2024/06/03 20:15

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()

  




原创粉丝点击