漫画Android:事件分发的过程是怎样的?

news2025/6/2 4:13:16

1
2
3
4
5
当用户触摸屏幕时,硬件层会捕获触摸信号,并将其转化为内核事件。
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()

  1. 事件产生:用户触摸屏幕,系统生成MotionEvent
  2. 根视图分发MotionEvent首先传递给当前Activity,然后依次传递到当前窗口的根视图(DecorView)。
  3. dispatchTouchEvent()DecorView调用自己的dispatchTouchEvent(),决定是否将事件向下分发。
  4. onInterceptTouchEvent() (ViewGroup)
    • 如果DecorViewViewGroup(通常是),它会调用onInterceptTouchEvent()来判断是否拦截事件。
    • 如果返回true(拦截),事件将直接传递给DecorViewonTouchEvent()
    • 如果返回false(不拦截),事件将继续向下分发给子View。
  5. 向下分发DecorView遍历其子View,找到触摸区域内的子View,并调用该子View的dispatchTouchEvent()。这个过程会递归地重复步骤4和5,直到事件到达最底层的View或者被某个ViewGroup拦截。
  6. onTouchEvent() (View/ViewGroup)
    • 如果事件被某个View或ViewGroup拦截(onInterceptTouchEvent()返回true),或者事件一直分发到了最底层的View且没有被任何父ViewGroup拦截,那么该View/ViewGroup的onTouchEvent()方法将被调用。
    • 如果onTouchEvent()返回true,表示该View/ViewGroup消费了事件,事件传递流程结束。
    • 如果onTouchEvent()返回false,表示该View/ViewGroup不处理事件,事件会回溯到其父ViewGroup的onTouchEvent()方法(如果父ViewGroup之前没有拦截该事件)。
  7. 事件未被处理:如果事件最终没有被任何View或ViewGroup处理(即所有onTouchEvent()都返回false),那么该事件会沿着View树向上回溯,最终可能会被Activity的onTouchEvent()方法处理。如果连Activity的onTouchEvent()也返回false,则该事件将被丢弃。

Android事件分发是一个自上而下分发、自下而上处理(如果未被处理)的过程。

6
7
8
9

ViewGroup事件分发流程

依葫芦画瓢!ViewGroup的事件分发流程围绕刚刚提到的三个核心方法展开:dispatchTouchEvent()onInterceptTouchEvent()onTouchEvent()

  1. 事件到达:当一个MotionEvent到达ViewGroup时,首先调用其dispatchTouchEvent()方法。
  2. 是否拦截?:在dispatchTouchEvent()内部,首先调用onInterceptTouchEvent()来判断ViewGroup是否要拦截这个事件。
    • 如果onInterceptTouchEvent()返回true (拦截)
      • 事件不再向下分发给子View
      • ViewGroup自身的onTouchEvent()方法会被调用,以处理该事件。
      • 如果onTouchEvent()返回true,表示事件被ViewGroup消费。
      • 如果onTouchEvent()返回false,表示事件未被ViewGroup消费,事件会回溯到其父ViewGrouponTouchEvent()(如果父ViewGroup之前没有拦截该事件)。
    • 如果onInterceptTouchEvent()返回false (不拦截)
      • ViewGroup会遍历其子View
      • 它会判断触摸点是否在某个子View的范围内。
      • 如果找到合适的子View,就调用该子ViewdispatchTouchEvent()方法,将事件继续向下传递。
      • 如果子ViewdispatchTouchEvent()返回true (子View消费了事件):整个事件分发流程结束。
      • 如果子ViewdispatchTouchEvent()返回false (子View未消费事件)ViewGroup会继续尝试将事件分发给下一个合适的子View
      • 如果所有子View都遍历完了,但都没有消费事件,或者根本没有子View:那么事件会回传给当前ViewGroup,调用其onTouchEvent()方法来处理。
        • 如果ViewGrouponTouchEvent()返回true,事件被ViewGroup消费。
        • 如果ViewGrouponTouchEvent()返回false,事件未被ViewGroup消费,会继续回溯到父ViewGroup

关键点:

  • 优先拦截onInterceptTouchEvent()优先于子ViewdispatchTouchEvent()被调用,它有“一票否决权”。
  • 消费即止:一旦某个ViewViewGrouponTouchEvent()返回true,表示它消费了该事件序列,后续事件将直接传递给它,不再进行分发。
  • 回溯机制:如果一个事件沿着分发路径一直没有被消费(所有onTouchEvent()都返回false),它会沿着调用链向上回溯,最终可能由ActivityonTouchEvent()处理。

内部逻辑(伪代码表示):

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; // 返回事件是否被处理
}

10

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2393456.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022 RoboCom 世界机器人开发者大赛-本科组(省赛)解题报告 | 珂学家

前言 题解 2022 RoboCom 世界机器人开发者大赛-本科组&#xff08;省赛&#xff09;。 感觉T5是最简单的&#xff0c;其他都不好做。 RC-u5 树与二分图 分值: 30分 思路: 容斥原理 树天然就是二分图&#xff0c;按深度d归类(偶数深度为S1&#xff0c;奇数深度为S2)&#x…

如何用ChatGPT提升学术长文质量

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

BKP(备份寄存器)和 RTC(实时时钟)

什么是BKP&#xff1f; 备份寄存器&#xff08;BackupRegister&#xff09;是42个16位的寄存器&#xff08;不同设备存在差异&#xff1a;20字节&#xff08;中容量和小容量&#xff09;/84字节&#xff08;大容量和互联型&#xff09;&#xff09;&#xff0c;可用来存储 最多…

【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 源码&#xff1a;https://github.com/LSH9832/edgeyolo 论文&#xff1a;https://arxiv.org/pdf/2302.07483 …

调试技巧总结

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

ubuntu安装blender并配置应用程序图标

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

基于LBS的上门代厨APP开发全流程解析

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

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容器技术&#xff0c;快速搭建一个完整的大数据环境。该环境包含以下核心组件&#xff1a; Hadoop HDFS/YARN&#xff08;分布式存储与资源调度&#xff09;Spark on YARN&#xff08;分布式计算…

【大模型】Bert

一、背景与起源 上下文建模的局限&#xff1a;在 BERT 之前&#xff0c;诸如 Word2Vec、GloVe 等词向量方法只能给出静态的词表示&#xff1b;而基于单向或浅层双向 LSTM/Transformer 的语言模型&#xff08;如 OpenAI GPT&#xff09;只能捕捉文本从左到右&#xff08;或右到…

3 分钟学会使用 Puppeteer 将 HTML 转 PDF

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

速通《Sklearn 与 TensorFlow 机器学习实用指南》

1.机器学习概览 1.1 什么是机器学习 机器学习是通过编程让计算机从数据中进行学习的科学。 1.2 为什么使用机器学习&#xff1f; 使用机器学习&#xff0c;是为了让计算机通过数据自动学习规律并进行预测或决策&#xff0c;无需显式编程规则。 1.3 机器学习系统的类型 1.…

Ubuntu 下搭建ESP32 ESP-IDF开发环境,并在windows下用VSCode通过SSH登录Ubuntu开发ESP32应用

Ubuntu 下搭建ESP32 ESP-IDF开发环境&#xff0c;网上操作指南很多&#xff0c;本来一直也没有想过要写这么一篇文章。因为我其实不太习惯在linux下开发应用&#xff0c;平时更习惯windows的软件操作&#xff0c;只是因为windows下开发ESP32的应用编译时太慢&#xff0c;让人受…

NodeMediaEdge接入NodeMediaServer

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

【Java基础-环境搭建-创建项目】IntelliJ IDEA创建Java项目的详细步骤

在Java开发的世界里&#xff0c;选择一个强大的集成开发环境&#xff08;IDE&#xff09;是迈向高效编程的第一步。而IntelliJ IDEA无疑是Java开发者中最受欢迎的选择之一。它以其强大的功能、智能的代码辅助和简洁的用户界面&#xff0c;帮助无数开发者快速构建和部署Java项目…

PHP7+MySQL5.6 查立得源码授权系统DNS验证版

# PHP7MySQL5.6 查立得源码授权系统DNS验证版 ## 一、系统概述 本系统是一个基于PHP7和MySQL5.6的源码授权系统&#xff0c;使用DNS TXT记录验证域名所有权&#xff0c;实现对软件源码的授权保护。 系统支持多版本管理&#xff0c;可以灵活配置不同版本的价格和下载路径&#…

【QQ音乐】sign签名| data参数加密 | AES-GCM加密 | webpack (下)

1.目标 网址&#xff1a;https://y.qq.com/n/ryqq/toplist/26 我们知道了 sign P(n.data)&#xff0c;其中n.data是明文的请求参数 2.webpack生成data加密参数 那么 L(n.data)就是密文的请求参数。返回一个Promise {<pending>}&#xff0c;所以L(n.data) 是一个异步函数…

3D虚拟工厂

1、在线体验 3D虚拟工厂在线体验 vue3three.jsblender 2、功能介绍 1. 全屏显示功能2. 镜头重置功能3. 企业概况信息模块4. 标签隐藏/显示功能5. 模型自动旋转功能6. 办公楼分层分解展示7. 白天/夜晚 切换8. 场景资源预加载功能9. 晴天/雨天/雾天10. 无人机视角模式11. 行人…

http传输协议的加密

创建目录存放签证 [rootserver100 ~]# mkdir /etc/nginx/certs [rootserver100 ~]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/nginx/certs/timinglee.org.key -x509 -days 365 -out /etc/nginx/certs/timinglee.org.crt ..................................…