Android Input事件机制学习

2020-08-30  本文已影响0人  过期的薯条

1.引言

看《android源码设计模式》讲命令模式那章,介绍了下Input机制。让我联想起同事给我那篇关于Input事件机制的文档。于是决定自己琢磨琢磨,了解了解,Input机制的知识。
参考:
https://www.jianshu.com/p/faedef1910fe
https://www.jianshu.com/p/f05d6b05ba17
http://gityuan.com/2016/12/10/input-manager/

2.正题

2.1基本知识和概念

EventHub
EventHub,它主要是利用Linux的inotify和epoll机制,监听设备事件:包括设备插拔及各种触摸、按钮事件等,可以看做是一个不同设备的集线器,主要面向的是/dev/input目录下的设备节点,比如说/dev/input/event0上的事件就是输入事件,通过EventHub的getEvents就可以监听并获取该事件。

InputReader:
EventHub得到RowEvent之后,交给InputReader进行加工成我们需要的KeyEvent。并将Event传递给InputDispatcher,

InputDispatcher:
InputDispatcher负责将event传递给,Window。一个手机又多个Window,传递给哪个Window就是InputDispatcher 做的事。

image.png

2.2 如何将事件分发给上层应用

  /**
     * Creates a new input channel pair.  One channel should be provided to the input
     * dispatcher and the other to the application's input queue.
     * @param name The descriptive (non-unique) name of the channel pair.
     * @return A pair of input channels.  The first channel is designated as the
     * server channel and should be used to publish input events.  The second channel
     * is designated as the client channel and should be used to consume input events.
     */
    public static InputChannel[] openInputChannelPair(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        if (DEBUG) {
            Slog.d(TAG, "Opening input channel pair '" + name + "'");
        }
        return nativeOpenInputChannelPair(name);
    }


ViewRootImp#setView
1.创建Channel
2.将Channel传递给WMS
3.创建WindowInputEventReceiver
4.创建InputStage 责任链设计模式

image.png

上图并不是包装者模式,而是地地道道的责任链模式。构造方法中指定的对象作为是为Next赋值的。

最终执行到 ViewPostImeInputStage#processPointerEvent。进而走了DecorView#dispatchPointerEvent方法。

DecorView#dispatchPointerEvent最终会调用到

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

其中WindowCallBack.被Activity实现。所以会走进Activity#dispatchTouchEvent。

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

activity的getWindow() 就是我们的PhoneWindow。而PhoneWindow又是调用的。DecorView# dispatchTouchEvent方法 进入了 我们熟悉的事件传递过程。

ps技巧:Log.getStackTraceString(new Throwable()) 打印堆栈,帮我们分析函数调用过程

上一篇 下一篇

猜你喜欢

热点阅读