美文网首页
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