Android事件的产生和底层分发

Android底层事件分发机制-完结篇 本文书接上文继续讲经过底层处理后的事件,是怎么一步步分发到app层的,拨开上层开发者对输入事件的迷雾 阅读详情

目录

事件的产生

系统分发

EventHub

InputReader

InputDispatcher

接收事件


事件的产生

当屏幕被触摸,Linux内核会将硬件产生的触摸事件包装为Event存到/dev/input/event[x]目录下。

可以通过命令监控event

adb shell getevent

androidSource/system/core/toolbox目录下的getevent.c和sendevent.c是解析的实现

系统分发

EventHub

文件在frameworks/native/services/inputflinger/EventHub.cpp

EventHub主要是访问/dev/input下的所有设备节点,并将输入事件、设备节点的增删返给InputReader

InputReader

文件在frameworks/native/services/inputflinger/InputReader.cpp

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);
        oldGeneration = mGeneration;
        timeoutMillis = -1;
        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }
        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock
    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush();
}

依次调用方法

void TouchInputMapper::process(const RawEvent* rawEvent)
void TouchInputMapper::sync(nsecs_t when)
void TouchInputMapper::processRawTouches(bool timeout)
void TouchInputMapper::cookAndDispatch(nsecs_t when)
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags)
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
float xPrecision, float yPrecision, nsecs_t downTime)

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, int32_t actionButton, int32_t flags,
        int32_t metaState, int32_t buttonState, int32_t edgeFlags,
        const PointerProperties* properties, const PointerCoords* coords,
        const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
        float xPrecision, float yPrecision, nsecs_t downTime) {
    PointerCoords pointerCoords[MAX_POINTERS];
    PointerProperties pointerProperties[MAX_POINTERS];
    uint32_t pointerCount = 0;
    while (!idBits.isEmpty()) {
        uint32_t id = idBits.clearFirstMarkedBit();
        uint32_t index = idToIndex[id];
        pointerProperties[pointerCount].copyFrom(properties[index]);
        pointerCoords[pointerCount].copyFrom(coords[index]);

        if (changedId >= 0 && id == uint32_t(changedId)) {
            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        }

        pointerCount += 1;
    }

    ALOG_ASSERT(pointerCount != 0);

    if (changedId >= 0 && pointerCount == 1) {
        // Replace initial down and final up action.
        // We can compare the action without masking off the changed pointer index
        // because we know the index is 0.
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            action = AMOTION_EVENT_ACTION_UP;
        } else {
            // Can't happen.
            ALOG_ASSERT(false);
        }
    }

    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, actionButton, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    getListener()->notifyMotion(&args);
}
InputListenerInterface* InputReader::ContextImpl::getListener() {
    return mReader->mQueuedListener.get();
}
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& lis
Android事件分发机制一:事件是如何到达activity的? 我们来回顾一下:DecorView交给Activity处理,Activity直接交给PhoneWindow处理,PhoneWindow直接交给其内部的DecorView处理,而DecorView则直接调用父类ViewGroup的方法进行分发,ViewGroup则会按照具体的逻辑分发到整个控件树中感兴趣的子控件。前面我们讲到,view树的根节点可以是一个viewGroup,也可以是一个单独的view,因此,这里的派发就会有两种不同的方式:直接给view进行处理 or viewGroup进行事件分发。 阅读详情

相关推荐

Android 进阶——Framework 核心之Touch事件分发机制详细攻略(一)

Android 事件事件分发的对象、处理事件的对象、事件分发的流程四、事件分发的原理 引言 一般说来所有事件的本质都是由驱动打通硬件屏幕和操作系统的输入总线的,当手指去点击或者按下屏幕时都会产生对应的信号,由驱动往操作系统上传递,并提供对应的监听和响应机制,这也是为什么MotionEvent需要继承native 层InputEvent(其...

最美不过,心中有梦,身旁有你! 4242

Android面试题(27)-android的事件分发机制

今天开始写一点关于view的知识,先从最基本的讲吧,android的事件分发机制,其实在我看来,android的事件分发机制在现实生活中经常能看到,所以我觉得还是很好理解的;先看看生活中常见的一种情形吧;比如说,现在你所在的公司中有一项任务被派发下来了,项目经理把项目交给你的老大,你的老大老大手下有很多人,看了看觉得你做很合适,把这个任务交给你了;你一看觉得还行,你就接下来了;这么一个小小场景大概...

pgg_cold的博客 1万+

Android Input底层机制

本文旨在帮助上层开发者理清从底层事件处理分发到上层的全景图,揭开input系统事件产生分发机制的面纱,让我们清晰知道事件从哪来到哪去

jh1988abc的专栏 1533

彻底掌握Android touch事件的分发机制

文章目录1. 基本介绍1.1 MotionEvent1.2 控件的事件分发、拦截、消费1.3 大致流程图2. Activity对点击事件分发过程3.ViewGroup的touch事件分发过程3.1 宏观结构3.1 步骤1的具体代码及分析3.2 步骤 2 具体代码及分析3.3 步骤3具体代码及分析3.4 为什么 DOWN 事件如此特殊3.5 容易被遗漏的 CANCEL 事件4. View对touch事件的处理过程5. 总结 主要参考文献:任玉刚《Android开发艺术探索》 1. 基本介绍 1.1 Motio

天亮了的博客 1053

Android 面试:事件分发8连问(1)

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

2401_84010804的博客 1161

Android 面试:事件分发8连问,安卓基础面试题

当屏幕被触摸,Linux内核会将硬件产生的触摸事件包装为Event存到/dev/input/event[x]目录下 这样做的目的是将输入事件封装为通用的Event,供后续处理 [](()1.2 SystemServer部分 我们知道,当系统启动时,在SystemServer进程会启动一系列系统服务,如AMS,WMS等 其中还有一个就是我们管理事件输入的InputManagerService 这个服务就是用来负责与硬件通信,接受屏幕输入事件。 在其内部,会启动一个读线程,也就是InputReader,它会从系

m0_54851114的博客 526

Android——简单易懂说原理之View的点击事件分发机制

第一次写自定义View还是在14年春节,之前公司有个通信的项目,里面有个图形化展示OCC或者ODF的端子状态界面。最早都是用XML手动嵌套的,直接写死了一排是12个端子,一个子框里有6排。后来随着业务的增长,一排12个端子显然不能满足需求,一开始是手动写一排16个端子和一排8个端子的XML,终于有一天变为需要用户自定义端子排数和每排端子数了,于是自定义一个端子的View也不得不提上日程。 罗里吧嗦地说了一堆前言没进去正题,我的意思是说,自定义View很常见,在自定义view过程中,了解机制也很重要。 当然,

nanquan11的博客 564

Android面试题精选:讲一讲-Android-的事件分发机制

本来写到这就结束了,但回顾一遍还是打算给大家稍微总结一下。需要总结的小点:1、Android 事件分发总是遵循 Activity => ViewGroup => View 的传递顺序;2、onTouch()执行总优先于onClick()Android事件分发机制详解:史上最全面、最易懂,所以直接引用一下其中的图片。Activity 的事件分发示意图ViewGroup 事件分发示意图View 的事件分发示意图事件分发工作流程总结。

2401_84149381的博客 563

Android触摸事件分发机制详解:从底层流转到滑动冲突与多点触碰

触摸事件是Android交互的基石,其分发机制直接影响点击响应、滑动流畅度与自定义控件行为。事件并非从Activity开始,而是由硬件驱动经输入子系统、InputDispatcher、InputChannel流转至ViewRootImpl,最终进入View树。在ViewGroup中,dispatchTouchEvent、onInterceptTouchEvent与onTouchEvent三个方法分工协作,DOWN事件负责锁定事件序列目标,MOVE阶段父容器可拦截并触发ACTION_CANCEL。理解这套机制

weixin_29168153的博客 229

Android 事件分发机制深度解析——原理、源码与实战综合总结

在自定义 ViewGroup 的中,利用水平滑动距离大于垂直距离且超过触摸斜率时拦截,然后在中根据手指移动距离控制内容视图的平移,实现侧滑菜单。三个方法各司其职分发、拦截(仅 ViewGroup)、消费。U 型传递:事件自顶向下分发,若无人消费则自底向上回传。事件序列锁定DOWN的消费决定序列归属,后续事件直送目标,中途拦截则发送CANCEL后接管。灵活拦截与反拦截:外部拦截法和内部拦截法结合解决绝大部分滑动冲突。源码即真相:深入等关键方法,才能彻底理解行为背后的细节。

天空之城 337

Android事件分发机制深入浅出全面解析和优化指南

在Android开发中,自定义事件分发逻辑是处理复杂用户交互的关键。通过自定义事件分发逻辑,开发者可以精确控制触摸事件的传递和处理方式,从而实现更丰富的交互效果和更优秀的用户体验。要实现自定义事件分发逻辑,通常需要重写View或ViewGroup中的事件分发相关方法,如dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()。以下是一些建议的步骤和策略:1、明确需求:首先,要明确你的应用需要实现哪些特定的交互效果。

大模型大数据攻城狮的专栏 799

Java多态在Android开发中的应用:View事件分发机制解析

在Android开发中,View事件分发机制是非常重要的一部分。它决定了用户触摸屏幕等操作产生的事件如何在视图层次结构中传递和处理。本文的目的就是详细解析这个机制,并且探讨Java多态在其中的应用,让开发者能更好地控制事件的处理流程,范围涵盖了从基本概念到实际项目应用的各个方面。本文先介绍核心概念,包括Java多态和View事件分发机制,解释它们之间的联系。接着阐述核心算法原理和具体操作步骤,给出数学模型和公式帮助理解。然后通过项目实战展示代码实现和解读。再介绍实际应用场景和推荐相关工具资源。

Java大师兄的博客 1164

GOM引擎单机传奇架设全攻略——从DBC2000配置到登录器生成

本文详细解析了使用GOM引擎架设单机传奇的完整流程,从DBC2000的安装配置、服务端部署、引擎控制器设置,到登录器生成与客户端补丁放置。文章重点解决了单机架设中的常见问题,如数据库路径配置、IP地址设置及Key.lic文件处理,旨在帮助玩家快速搭建稳定的个人游戏环境,体验GM乐趣。

weixin_28318011的博客 627

2.数字芯片时序正确的前提—Max-transition

芯片物理设计中最基本的Max-transition检查

weixin_43868998的博客 5418

【PCIe DL_Feature详解】

   Data Link Control and Management State Machine在PCIe Gen4引入了DL_Feature这个状态,该状态主要用来协商PCIe link 两端是否支持新的DL Feature,目前为止DL Feature只引入了Scaled Flow Control 来提高Gen4及以上的效率。   DL_Feature 这个状态是可选的,当 Data Link Feature Extended Capability中Data Link Feature Exchang

sinat_38294441的博客 3232

告别GUI点点点:Formality形式化验证的TCL脚本自动化实战(附完整脚本)

本文详细介绍了如何通过TCL脚本实现Formality形式化验证的全流程自动化,显著提升验证效率并降低错误率。内容涵盖脚本框架解析、参数化设计、验证报告生成及团队协作策略,特别适合芯片设计工程师摆脱传统GUI操作,实现300%以上的效率提升。

weixin_33737134的博客 282

在 SAP S/4HANA 里把 OData Client Proxy 用顺手,借助 Service Consumption Model 2.0 提前打通远程 OData 调用

摘要:本文探讨了在SAP S/4HANA集成开发中调用外部OData服务的解决方案。传统ABAP代码直接调用方式存在诸多不便,而OData Client Proxy提供了更稳定的途径。文章详细介绍了如何通过Service Consumption Model 2.0在SAP BTP生成模型类,并将其移植到SAP S/4HANA进行适配改造,最终注册为可用的OData Proxy Client。该方法适用于较新版本的SAP S/4HANA系统,通过源码替换实现模型转换,为系统集成提供了高效的类型安全调用方案。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1089

【YOLOv10[基础]】热力图可视化实践③ | 热力图脚本升级 | 优化可视化效果 | 论文必备 | GradCAMPlusPlus, GradCAM, XGradCAM, EigenCAM等

热力图可视化实践③ | 热力图脚本升级 | 优化可视化效果 | 论文必备 | 遥遥领先

静谧、淡雅 3217

GStreamer —— 2.1、Windows搭建GStreamer环境,Qt加载GStreamer库后运行 - “教程1:Hello world!“(附:完整源码)

GStreamer —— 2、Windows搭建GStreamer环境,Qt加载GStreamer库后运行"教程1:Hello world!"

796

ESP32学习笔记06-UART 的485 通讯模式

通信方式选择UART 控制器支持多种通信模式,使用函数 uart_set_mode() 可以选择模式。选择特定模式后,UART 驱动程序将处理已连接 UART 设备的相应行为。例如,主机开始向 Tx FIFO 缓冲区写入数据时,UART 驱动程序会自动置位 RTS 管脚(逻辑 1);最后一位数据传输完成后,驱动程序就会取消置位 RTS 管脚(逻辑 0)。要使用此模式,软件。

Car12 2476

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

上一篇: 从代理模式到mockito原理
robert_chao
博客等级 码龄15年 265粉丝 119原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值