美文网首页
Android Input事件机制学习

Android Input事件机制学习

作者: 过期的薯条 | 来源:发表于2020-08-30 14:33 被阅读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 如何将事件分发给上层应用

  • InputChannel: 底层和上层通信的核心(非binder通信而是Socket通信)。openInputChannelPair方法中文翻译就是创建,一对input通道,应用层持有一个channel,InputDispatcher持有另外一个。这样形成c/s端。应用层作为Server,InputDispatcher作为Client.进而传递Event
  /**
     * 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);
    }

  • WindowInputEventReceiver:上层接受事件的入口。
    原英文解释:Provides a low-level mechanism for an application to receive input events

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()) 打印堆栈,帮我们分析函数调用过程

相关文章

网友评论

      本文标题:Android Input事件机制学习

      本文链接:https://www.haomeiwen.com/subject/pwtesktx.html