漫画Android:事件分发的过程是怎样的?
当用户触摸屏幕时,硬件层会捕获触摸信号,并将其转化为内核事件。
Android系统会通过InputManagerService和WindowManagerService等服务将这些事件包装成MotionEvent
对象,并将其传递给Activity的dispatchTouchEvent()
方法中,Activity会先将事件分发给Window处理,Window调用superDispatchTouchEvent()
方法,将事件交给 PhoneWindow
处理,然后 PhoneWindow
将事件传递给当前窗口的根视图(通常是DecorView,一个FrameLayout)。
DecorView是PhoneWindow的顶级视图,它是所有应用UI的容器。从这里开始,事件分发就进入了应用程序的视图层级。
即,事件收集之后最先传递给Activity
,随后依次向下传递:
Activity ——> Window ——> …… ——> DecorView ——> ViewGroup ——> …… ——> View
事件分发的流程
整个事件分发过程主要围绕MotionEvent
对象展开,并且涉及三个关键方法:dispatchTouchEvent()
、onInterceptTouchEvent()
和onTouchEvent()
。
- 事件产生:用户触摸屏幕,系统生成
MotionEvent
。 - 根视图分发:
MotionEvent
首先传递给当前Activity
,然后依次传递到当前窗口的根视图(DecorView
)。 dispatchTouchEvent()
:DecorView
调用自己的dispatchTouchEvent()
,决定是否将事件向下分发。onInterceptTouchEvent()
(ViewGroup):- 如果
DecorView
是ViewGroup
(通常是),它会调用onInterceptTouchEvent()
来判断是否拦截事件。 - 如果返回
true
(拦截),事件将直接传递给DecorView
的onTouchEvent()
。 - 如果返回
false
(不拦截),事件将继续向下分发给子View。
- 如果
- 向下分发:
DecorView
遍历其子View,找到触摸区域内的子View,并调用该子View的dispatchTouchEvent()
。这个过程会递归地重复步骤4和5,直到事件到达最底层的View或者被某个ViewGroup拦截。 onTouchEvent()
(View/ViewGroup):- 如果事件被某个View或ViewGroup拦截(
onInterceptTouchEvent()
返回true
),或者事件一直分发到了最底层的View且没有被任何父ViewGroup拦截,那么该View/ViewGroup的onTouchEvent()
方法将被调用。 - 如果
onTouchEvent()
返回true
,表示该View/ViewGroup消费了事件,事件传递流程结束。 - 如果
onTouchEvent()
返回false
,表示该View/ViewGroup不处理事件,事件会回溯到其父ViewGroup的onTouchEvent()
方法(如果父ViewGroup之前没有拦截该事件)。
- 如果事件被某个View或ViewGroup拦截(
- 事件未被处理:如果事件最终没有被任何View或ViewGroup处理(即所有
onTouchEvent()
都返回false
),那么该事件会沿着View树向上回溯,最终可能会被Activity的onTouchEvent()
方法处理。如果连Activity的onTouchEvent()
也返回false
,则该事件将被丢弃。
Android事件分发是一个自上而下分发、自下而上处理(如果未被处理)的过程。
ViewGroup事件分发流程
依葫芦画瓢!ViewGroup
的事件分发流程围绕刚刚提到的三个核心方法展开:dispatchTouchEvent()
、onInterceptTouchEvent()
和onTouchEvent()
。
- 事件到达:当一个
MotionEvent
到达ViewGroup
时,首先调用其dispatchTouchEvent()
方法。 - 是否拦截?:在
dispatchTouchEvent()
内部,首先调用onInterceptTouchEvent()
来判断ViewGroup
是否要拦截这个事件。- 如果
onInterceptTouchEvent()
返回true
(拦截):- 事件不再向下分发给子
View
。 ViewGroup
自身的onTouchEvent()
方法会被调用,以处理该事件。- 如果
onTouchEvent()
返回true
,表示事件被ViewGroup
消费。 - 如果
onTouchEvent()
返回false
,表示事件未被ViewGroup
消费,事件会回溯到其父ViewGroup
的onTouchEvent()
(如果父ViewGroup
之前没有拦截该事件)。
- 事件不再向下分发给子
- 如果
onInterceptTouchEvent()
返回false
(不拦截):ViewGroup
会遍历其子View
。- 它会判断触摸点是否在某个子
View
的范围内。 - 如果找到合适的子
View
,就调用该子View
的dispatchTouchEvent()
方法,将事件继续向下传递。 - 如果子
View
的dispatchTouchEvent()
返回true
(子View
消费了事件):整个事件分发流程结束。 - 如果子
View
的dispatchTouchEvent()
返回false
(子View
未消费事件):ViewGroup
会继续尝试将事件分发给下一个合适的子View
。 - 如果所有子
View
都遍历完了,但都没有消费事件,或者根本没有子View
:那么事件会回传给当前ViewGroup
,调用其onTouchEvent()
方法来处理。- 如果
ViewGroup
的onTouchEvent()
返回true
,事件被ViewGroup
消费。 - 如果
ViewGroup
的onTouchEvent()
返回false
,事件未被ViewGroup
消费,会继续回溯到父ViewGroup
。
- 如果
- 如果
关键点:
- 优先拦截:
onInterceptTouchEvent()
优先于子View
的dispatchTouchEvent()
被调用,它有“一票否决权”。 - 消费即止:一旦某个
View
或ViewGroup
的onTouchEvent()
返回true
,表示它消费了该事件序列,后续事件将直接传递给它,不再进行分发。 - 回溯机制:如果一个事件沿着分发路径一直没有被消费(所有
onTouchEvent()
都返回false
),它会沿着调用链向上回溯,最终可能由Activity
的onTouchEvent()
处理。
内部逻辑(伪代码表示):
public boolean dispatchTouchEvent(MotionEvent event) {boolean handled = false; // 标记事件是否被处理// 1. 调用 onInterceptTouchEvent() 判断是否拦截if (onInterceptTouchEvent(event)) {// 2. 如果 onInterceptTouchEvent() 返回 true (拦截)// 则事件不再向下分发给子View,而是直接交给当前ViewGroup的 onTouchEvent() 处理handled = onTouchEvent(event);} else {// 3. 如果 onInterceptTouchEvent() 返回 false (不拦截)// 则遍历子View,尝试将事件分发给它们// 查找触摸点所在的子View,并调用其 dispatchTouchEvent()// 伪代码:// for (int i = 0; i < getChildCount(); i++) {// View child = getChildAt(i);// if (child.isTouchedInBounds(event)) { // 检查触摸点是否在子View范围内// if (child.dispatchTouchEvent(event)) { // 递归调用子View的dispatchTouchEvent()// handled = true; // 子View消费了事件// break; // 停止遍历,事件已被处理// }// }// }// 4. 如果所有子View都没有消费事件 (handled 仍为 false)// 或者根本没有子View// 则将事件交给当前ViewGroup的 onTouchEvent() 处理if (!handled) {handled = onTouchEvent(event);}}return handled; // 返回事件是否被处理
}
相关文章:

漫画Android:事件分发的过程是怎样的?
当用户触摸屏幕时,硬件层会捕获触摸信号,并将其转化为内核事件。 Android系统会通过InputManagerService和WindowManagerService等服务将这些事件包装成MotionEvent对象,并将其传递给Activity的dispatchTouchEvent()方法中,Activi…...

2022 RoboCom 世界机器人开发者大赛-本科组(省赛)解题报告 | 珂学家
前言 题解 2022 RoboCom 世界机器人开发者大赛-本科组(省赛)。 感觉T5是最简单的,其他都不好做。 RC-u5 树与二分图 分值: 30分 思路: 容斥原理 树天然就是二分图,按深度d归类(偶数深度为S1,奇数深度为S2)&#x…...
什么是MCP技术,跟http技术有什么区别
什么是MCP技术? MCP(Model Context Protocol,模型上下文协议)是一种开源协议,旨在标准化大型语言模型(LLM)与外部数据源和工具之间的集成方式。 核心功能 上下文管理:保存对话历史…...

如何用ChatGPT提升学术长文质量
目录 一、关于让人工智能充当评审专家 二、关于分批次输入论文内容 三、来看看提示词 大家好这里是学术Anan,官网👉AIWritePaper~ 论文完成初稿之后,一般情况下,宝子们还需要找专家给我们提出评审意见。找专家评审其实并不容易…...

BKP(备份寄存器)和 RTC(实时时钟)
什么是BKP? 备份寄存器(BackupRegister)是42个16位的寄存器(不同设备存在差异:20字节(中容量和小容量)/84字节(大容量和互联型)),可用来存储 最多…...
springboot配置cors拦截器与cors解释
文章目录 cors?代码 cors? CORS(跨域资源共享)的核心机制是 由后端服务器(bbb.com)决定是否允许前端(aaa.com)的跨域请求 当浏览器访问 aaa.com 的页面,并向 bbb.com/list 发起请求时&#…...

【EdgeYOLO】《EdgeYOLO: An Edge-Real-Time Object Detector》
Liu S, Zha J, Sun J, et al. EdgeYOLO: An edge-real-time object detector[C]//2023 42nd Chinese Control Conference (CCC). IEEE, 2023: 7507-7512. CCC-2023 源码:https://github.com/LSH9832/edgeyolo 论文:https://arxiv.org/pdf/2302.07483 …...
Python打卡 DAY 38
知识点回顾: Dataset类的__getitem__和__len__方法(本质是python的特殊方法)Dataloader类minist手写数据集的了解 作业:了解下cifar数据集,尝试获取其中一张图片 import torch import torch.nn as nn import torch.opt…...

调试技巧总结
目录 一.调试1.什么是调试2.调试语义的分类2.1 静态语义2.2 动态语义 二.实用的调试技巧1.屏蔽代码2.借助打印3.查看汇编代码4.调试技巧总结 一.调试 1.什么是调试 调试,通俗易懂地说就是不断排查代码的错误,进行修正的过程,在写代码的时候…...

ubuntu安装blender并配置应用程序图标
ubuntu安装blender并配置应用程序图标 下载blender安装包解压缩并安装启动blender添加应用程序启动图标 下载blender安装包 blender中文服务站的下载网址 这里选择Linux 64位的Blender 4.2.4 LTS。下载速度很快。下载得到 解压缩并安装 将下载的压缩包放在/opt目录下&#…...

基于LBS的上门代厨APP开发全流程解析
上门做饭将会取代外卖行业成为新一轮的创业风口吗?杭州一位女士的3菜一汤88元套餐引爆社交网络,这个包含做饭、洗碗、收拾厨房的全套服务,正在重新定义"到家经济"的边界。当25岁的研究生系着围裙出现在客户厨房,当年轻姑…...

Redisson学习专栏(三):高级特性与实战(Spring/Spring Boot 集成,响应式编程,分布式服务,性能优化)
文章目录 前言一、Spring Boot深度整合实战1.1 分布式缓存管理1.2 声明式缓存1.3 响应式编程 二、分布式服务治理2.1 服务端实现2.2 客户端调用2.3 高级特性2.4 服务治理功能 三、分布式任务调度引擎四、连接池配置与网络参数调优4.1 连接池配置4.2 网络参数调优4.3 集群模式特…...

华为欧拉系统中部署FTP服务与Filestash应用:实现高效文件管理和共享
华为欧拉系统中部署FTP服务与Filestash应用:实现高效文件管理和共享 前言一、相关服务介绍1.1 Huawei Cloud EulerOS介绍1.2 Filestash介绍1.3 华为云Flexus应用服务器L实例介绍二、本次实践介绍2.1 本次实践介绍2.2 本次环境规划三、检查云服务器环境3.1 登录华为云3.2 SSH远…...

基于Docker和YARN的大数据环境部署实践最新版
基于Docker和YARN的大数据环境部署实践 目的 本操作手册旨在指导用户通过Docker容器技术,快速搭建一个完整的大数据环境。该环境包含以下核心组件: Hadoop HDFS/YARN(分布式存储与资源调度)Spark on YARN(分布式计算…...

【大模型】Bert
一、背景与起源 上下文建模的局限:在 BERT 之前,诸如 Word2Vec、GloVe 等词向量方法只能给出静态的词表示;而基于单向或浅层双向 LSTM/Transformer 的语言模型(如 OpenAI GPT)只能捕捉文本从左到右(或右到…...
《Go小技巧易错点100例》第三十四篇
本期分享: 1.sync.Mutex锁复制导致的异常 2.Go堆栈机制下容易导致的并发问题 sync.Mutex锁复制导致的异常 以下代码片段存在一个隐蔽的并发安全问题: type Counter struct {sync.MutexCount int }func foo(c Counter) {c.Lock()defer c.Unlock()…...
vue3+element-plus el-date-picker日期、年份筛选设置本周、本月、近3年等快捷筛选
一、页面代码: <template> <!-- 日期范围筛选框 --> <el-date-picker v-model"dateRange" value-format"YYYY-MM-DD" type"daterange" range-separator"至" start-placeholder"开始日期" end-…...
Vue 技术文档
一、引言 Vue 是一款用于构建用户界面的渐进式 JavaScript 框架,具有易上手、高性能、灵活等特点,能够帮助开发者快速开发出响应式的单页面应用。本技术文档旨在全面介绍 Vue 的相关技术知识,为开发人员提供参考和指导。 二、环境搭建 2.1…...

3 分钟学会使用 Puppeteer 将 HTML 转 PDF
需求背景 1、网页存档与文档管理 需要将网页内容长期保存或归档为PDF,确保内容不被篡改或丢失,适用于法律文档、合同、技术文档等场景。PDF格式便于存储和检索。 2、电子报告生成 动态生成的HTML内容(如数据分析报告、仪表盘)需导出为PDF供下载或打印。PDF保留排版和样…...

速通《Sklearn 与 TensorFlow 机器学习实用指南》
1.机器学习概览 1.1 什么是机器学习 机器学习是通过编程让计算机从数据中进行学习的科学。 1.2 为什么使用机器学习? 使用机器学习,是为了让计算机通过数据自动学习规律并进行预测或决策,无需显式编程规则。 1.3 机器学习系统的类型 1.…...

Ubuntu 下搭建ESP32 ESP-IDF开发环境,并在windows下用VSCode通过SSH登录Ubuntu开发ESP32应用
Ubuntu 下搭建ESP32 ESP-IDF开发环境,网上操作指南很多,本来一直也没有想过要写这么一篇文章。因为我其实不太习惯在linux下开发应用,平时更习惯windows的软件操作,只是因为windows下开发ESP32的应用编译时太慢,让人受…...
[FreeRTOS- 野火] - - - 临界段
一、介绍 临界段最常出现在对一些全局变量进行操作的场景。 1.1 临界段的定义 临界段是指在多任务系统中,一段需要独占访问共享资源的代码。在这段代码执行期间,必须确保没有任何其他任务或中断可以访问或修改相同的共享资源。 临界段的主要目的是防…...
【洛谷P9303题解】AC代码- [CCC 2023 J5] CCC Word Hunt
在CCC单词搜索游戏中,单词可以隐藏在字母网格中,以直线或直角的方式排列。以下是对代码的详细注释和解题思路的总结: 传送门: https://www.luogu.com.cn/problem/P9303 代码注释 #include <iostream> #include <vecto…...

NodeMediaEdge接入NodeMediaServer
如何使用NME接入NMS 简介 NodeMediaEdge是一款部署在监控摄像机网络前端中,拉取Onvif或者rtsp/rtmp/http视频流并使用rtmp/kmp推送到公网流媒体服务器的工具。 通过云平台协议注册到NodeMediaServer后,可以同NodeMediaServer结合使用。使用图形化的管理…...

【Java基础-环境搭建-创建项目】IntelliJ IDEA创建Java项目的详细步骤
在Java开发的世界里,选择一个强大的集成开发环境(IDE)是迈向高效编程的第一步。而IntelliJ IDEA无疑是Java开发者中最受欢迎的选择之一。它以其强大的功能、智能的代码辅助和简洁的用户界面,帮助无数开发者快速构建和部署Java项目…...
WebSocket指数避让与重连机制
1. 引言 在现代Web应用中,WebSocket技术已成为实现实时通信的重要手段。与传统的HTTP请求-响应模式不同,WebSocket建立持久连接,使服务器能够主动向客户端推送数据,极大地提升了Web应用的实时性和交互体验。然而,在实…...
DrissionPage WebPage模式:动态交互与高效爬取的完美平衡术
在Python自动化领域,开发者常面临两难选择:Selenium虽能处理动态页面但效率低下,Requests库轻量高效却难以应对JavaScript渲染。DrissionPage的WebPage模式创新性地将浏览器控制与数据包收发融为一体,为复杂网页采集场景提供了全新…...
adb查看、设置cpu相关信息
查内存 adb shell dumpsys meminfo查CPU top -m 10打开 system_monitor adb shell am start -n eu.chainfire.perfmon/.LaunchActivity设置CPU的核心数 在/sys/devices/system/cpu目录下可以看到你的CPU有几个核心,如果是双核,就是cpu0和cpu1,…...

PHP7+MySQL5.6 查立得源码授权系统DNS验证版
# PHP7MySQL5.6 查立得源码授权系统DNS验证版 ## 一、系统概述 本系统是一个基于PHP7和MySQL5.6的源码授权系统,使用DNS TXT记录验证域名所有权,实现对软件源码的授权保护。 系统支持多版本管理,可以灵活配置不同版本的价格和下载路径&#…...
68元开发板,开启智能硬件新篇章——明远智睿SSD2351深度解析
在智能硬件开发领域,开发板的选择至关重要。它不仅关系到项目的开发效率,还直接影响到最终产品的性能与稳定性。而今天,我要为大家介绍的这款明远智睿SSD2351开发板,仅需68元,却拥有远超同价位产品的性能与功能&#x…...