Android事件分发机制

1. 触摸事件的定义

Android系统处理用户交互的核心机制之一,它决定了触摸事件如何从系统传递到应用中具体组件并最终被处理消费。它的实现是基于责任链模式,由于触摸事件是包含ACTION_DOWNACTION_MOVE以及ACTION_UP的一组事件,当ACTION_DOWN事件交由某个组件处理后,这组事件剩余事件后续都由它处理。


2. 系统层事件传递过程

  • 触摸事件发生后,**IMS(Input Manager Service)**接收事件,**IRS(Input Reader)**读取事件,**IDS(Input Dispatcher)**分发事件。
  • 通过管道跨进程将事件信息传递到对应应用操作的ActivityViewRootImpl对象中。
  • ViewRootImpl创建时初始化了**IER(InputEventReceiver)**对象,IER持有管道,因此该跨进程得以实施。
  • ViewRootImpl拿到触摸事件后,将其封装成一个Message对象,传递到**AT(ActivityThread)**的MsgQ(Message Queue)中。
    • 如果触摸事件在5秒内未被处理,则系统会弹出**ANR(Application Not Responding)**提示。
    • 正常交由ActivitydispatchTouchEvent方法执行,Activity的分发方法是应用处理触摸事件的入口。

3. 应用层事件处理消费

包含三个方法:分发拦截消费

3.1 Activity的分发方法

  • 首先执行ActivitydispatchTouchEvent方法:
    • 如果返回true,则交由Activity消费。
    • 如果返回false,则交由ActivityonTouchEvent方法处理(无论返回值是什么都不处理)。
  • 默认返回时会走到Activity的顶层布局DecorView中。

3.2 DecorViewViewGroup的处理规则

  • DecorView本身是一个LinearLayout(即ViewGroup),无论是DecorView还是其子ViewGroup,都遵循以下规则:
    1. 先执行本身的dispatchTouchEvent方法:
      • 如果返回true,代表处理消费事件。
      • 如果返回false,交由父组件的onTouchEvent方法执行。
    2. 默认情况执行本身的onInterceptTouchEvent方法:
      • 如果返回true,则交由自己的onTouchEvent方法处理。
      • 如果返回false,则继续往下分发。
    3. 默认情况下,如果有子View被命中 ,则继续分发;否则相当于返回true,由自己处理。
  • 对于ViewGrouponTouchEvent方法:
    • 返回true,表示消费处理。
    • 返回false,则交由父组件的onTouchEvent方法处理。

3.3 View的处理规则

  • View组件只有dispatchTouchEventonTouchEvent方法。
    • dispatchTouchEvent方法返回true,则代表事件由自己处理消费。
    • 返回false,则交由父组件的onTouchEvent方法处理。
    • 默认情况下,根据View是否可点击:
      • 不可点击 :交由父组件的onTouchEvent方法处理。
      • 可点击 :自己执行onTouchEvent方法。
  • 消费方法执行优先级OnTouchListener > onTouchEvent > OnClickListener

4. 事件分发解决冲突

4.1 同向滑动冲突(如ScrollView包裹ListView

  1. 使用官方标准的NestedScrollView,内部通过同步状态来处理事件的消费。
  2. 使用内部模式外部模式 处理事件的消费:
    • 外部模式 :处理父组件的onInterceptTouchEvent方法,根据条件在ACTION_MOVE事件中返回false
    • 内部模式 :子组件通过requestDisallowInterceptTouchEvent方法申请父组件不拦截。
  3. 禁用子组件的事件消费:适用于应用数据量较小且能完全展示的情况。

4.2 不同方向滑动冲突

  1. 根据滑动方向处理事件消费。

4.3 混合情况

  1. 根据实际的业务情况来找到解决方案。

5. 流程图


相关推荐
AI人工智能+电脑小能手7 小时前
【大白话说Java面试题 第84题】【Mysql篇】第14题:为什么用 InnoDB 存储引擎的表建议用整型的自增主键?
java·开发语言·数据库·mysql·面试
小江的记录本7 小时前
【JVM虚拟机】JVM调优:常用JVM参数、调优核心指标、OOM排查、GC日志分析、Arthas工具使用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
swipe9 小时前
DeepAgents 多 Agent 深度调研助手工程实战:从 createDeepAgent 到可控调研工作流
javascript·面试·langchain
moMo9 小时前
JavaScript 变量提升,执行上下文里的各种门道
javascript·面试
UTF_810 小时前
一次NSMutableAttributedString误用的思考
ios·面试·github
程序员卷卷狗10 小时前
Java转Go面试速记:Go基础22问,一篇理清高频易错点一篇理清高频易错点
java·面试·golang
swipe11 小时前
DeepAgents middleware 工程实战:把复杂 Agent 的运行时基建交给可组合中间件
前端·面试·llm
小江的记录本12 小时前
【JVM虚拟机】类加载机制:类加载全流程:加载→验证→准备→解析→初始化(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·算法·安全·spring·面试
西安邮电大学13 小时前
Redis为什么快?
java·redis·后端·其他·面试
折哥的程序人生 · 物流技术专研13 小时前
《Java 100 天进阶之路》第39篇:Java泛型方法的定义和使用
java·开发语言·后端·面试·求职招聘