Android事件流程详解

网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述android事件背后的故事,话不多说,上干货。

android整个事件流程主要牵扯到dispatchTouchEvent(),onInterceptTouchEvent(),

onTouchEvent()这三个方法,下表来说明这三个方法的功能和分布场景:

表1:

方法名称 功解解说 Activity ViewGroup View
dispatchTouchEvent() 事件分发 YES YES YES
onInterceptTouchEvent() 事件拦截 NO YES NO
onTouchEvent() 事件处理 YES YES YES

先来分析下Touch事件:所有Touch事件发生时会调用当前Activity的dispatchTouchEvent()方

法来分发事件,Activity的dispatchTouchEvent()方法最终会调用PhoneWindow类中的

superDispatchTouchEvent方法,最终逻辑就是该activity会调用ViewGroup类中的

dispatchTouchEvent()进行隧道式分发事件(按布局元素由外向内分发),如本案例中的分发流程

为TouchTraining    ->  TouchViewGroup -> TouchView,需要注意的是,当你在Activit中的

dispatchTouchEvent()中直接返回具体的布尔值(无论是true还是false),Touch事件直接会被

消费在该方法中,不会再进行下来的事件分发流程,因此必须在activity的dispatchTouchEvrent

返回super.dispatchTouchEvent()来进行事件分发流程。下面进行案例说明分析:

首先在定义自己的View和ViewGroup,重写表1它们各自支持的事件流程方法,我这里自定ViewGroup

继承的是LinearLayout(只要继承的是ViewGroup都一样),然后分别在Activity的布局文件中加入自定

义的控件,接着在Activity中也重写它支持的事件流程方法。

activity_touchtrain.xml

<com.training.cj.mytraining.view.TouchViewGroupxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="300dp"android:layout_height="300dp"android:background="@android:color/holo_green_dark"><com.training.cj.mytraining.view.TouchViewandroid:layout_width="150dp"android:layout_height="150dp"android:background="@android:color/holo_red_dark" />
</com.training.cj.mytraining.view.TouchViewGroup>

TouchView(自定义View类)

@Override
public boolean dispatchTouchEvent(MotionEvent event) {Log.e(TAG, "dispatchTouchEvent分发事件"+ TouchEventUtil.getTouchAction(event.getAction()));return super.dispatchTouchEvent(event);
}@Override
public boolean onTouchEvent(MotionEvent ev) {Log.e(TAG, "onTouchEvent处理事件"+ TouchEventUtil.getTouchAction(ev.getAction()));return super.onTouchEvent(ev);
}

TouchViewGroup(自定义ViewGroup类)

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {Log.e(TAG, "dispatchTouchEvent分发事件" + TouchEventUtil.getTouchAction(ev.getAction()));return super.dispatchTouchEvent(ev);
}@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {Log.e(TAG, "onInterceptTouchEvent拦截事件"+ TouchEventUtil.getTouchAction(ev.getAction()));return super.onInterceptTouchEvent(ev);
}@Override
public boolean onTouchEvent(MotionEvent ev) {Log.e(TAG, "onTouchEvent处理事件"+ TouchEventUtil.getTouchAction(ev.getAction()));return super.onTouchEvent(ev);
}

TouchTraining(Activity)

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {Log.e(TAG, "dispatchTouchEvent分发事件"+ TouchEventUtil.getTouchAction(ev.getAction()));return super.dispatchTouchEvent(ev);
}@Override
public boolean onTouchEvent(MotionEvent ev) {Log.e(TAG, "onTouchEvent处理事件"+ TouchEventUtil.getTouchAction(ev.getAction()));return super.onTouchEvent(ev);
}

TouchEventUtils(工具类,获取当前事件类型)

public static String getTouchAction(int actionId) {String actionName = "Unknow:id=" + actionId;switch (actionId) {case MotionEvent.ACTION_DOWN:actionName = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:actionName = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:actionName = "ACTION_UP";break;case MotionEvent.ACTION_CANCEL:actionName = "ACTION_CANCEL";break;case MotionEvent.ACTION_OUTSIDE:actionName = "ACTION_OUTSIDE";break;}return actionName;
}


案例分析


方案1

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup false super.onInterceptTouchEvent(ev) super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_UP

结果分析:Touch事件开始,调用TouchTraining的dispatchTouchEvent把事件分发TouchViewGroup

的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回false,事件停止向下传递,同

时事件并没有消费,但由于该事件来自TouchTraining(Activity),所以最终返回给TouchTraining

的onTouchEvent进行消费。

方案2

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup true super.onInterceptTouchEvent(ev) super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_UP

结果分析:Touch事件由TouchTraining的dispatchTouchEvent不断向TouchViewGroup分发,

TouchViewGroup的dispatchTouchEvent返回true,TouchViewGroup在dispatchTouchEvent中不断消

费来自TouchTraining的dispatchTouchEvent分发的事件。

方案3

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup super.onInterceptTouchEvent(ev) true super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_UP

结果分析:Touch事件发生,调用TouchTraining的dispatchTouchEvent分发事件到TouchViewGroup

的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回super.onInterceptTouchEvent(ev)进

行事件分发,事件向下传递给TouchViewGroup的onInterceptTouchEvent,TouchViewGroup的onInterceptTouchEvent返回true,事件被拦截并传递给TouchViewGroup的onTouchEvent进行消费,TouchViewGroup的onTouchEvent返回super.dispatchTouchEvent(ev),对Touch事件未消费并返回给上级控件的onTouchEvent进行消费,由于TouchViewGroup的Touch事件来自TouchTraining,所以最后 由TouchTraining的onTouchEvent进行消费。

方案4

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup super.onInterceptTouchEvent(ev) false super.onTouchEvent(ev)
TouchView super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchTraining: onTouchEvent处理事件ACTION_UP

结果分析:Touch事件发生,调用TouchTraining的dispatchTouchEvent分发事件到TouchViewGroup的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回super.onInterceptTouchEvent(ev),继续分发向下传递事件到TouchViewGroup的onInterceptTouchEvent,TouchViewGroup的onInterceptTouchEvent返回false,继续分发向下传递事件到TouchView的dispatchTouchEvent,TouchView的dispatchTouchEvent返回super.dispatchTouchEvent(ev),继续分发向下传递事件到TouchView的onTouchEvent,TouchView的onTouchEvent返回super.onTouchEvent(ev),事件没有消费,返回给上级TouchViewGroup的onTouchEvent进行消费,TouchViewGroup的

onTouchEvent返回super.onTouchEvent(ev),继续返回给上级TouchTraining的onTouchEvent进行消费。

方案5:

条件
控件名称 dispatchTouchEvent返回值 onInterceptTouchEvent 返回值 onTouchEvent 返回值
TouchTraining super.dispatchTouchEvent(ev) ---- super.onTouchEvent(ev)
TouchViewGroup super.onInterceptTouchEvent(ev) false super.onTouchEvent(ev)
TouchView true ---- super.onTouchEvent(ev)

运行结果:

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: dispatchTouchEvent分发事件ACTION_DOWN

com.training.cj.mytraining E/TouchView: onTouchEvent处理事件ACTION_DOWN

com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent拦截事件ACTION_UP

com.training.cj.mytraining E/TouchView: dispatchTouchEvent分发事件ACTION_UP

com.training.cj.mytraining E/TouchView: onTouchEvent处理事件ACTION_UP

结果分析:Touch事件发生,调用TouchTraining的dispatchTouchEvent分发事件到TouchViewGroup的dispatchTouchEvent,该方法返回super.dispatchTouchEvent(ev),继续分发事件到TouchViewGroup的onInterceptTouchEvent,该方法返回false,继续分发事件到TouchView的dispatchTouchEvent,该方法返回super.dispatchTouchEvent(ev),继续分发事件到onTouchEvent,由于onTouchEvent返回true,表示消费了事件,Touch事件终止。

好了,本期的Touch事件分析到这里就结束了,另外,还有一个小细节需要注意的是,在View和View Group中的onTouchEvent方法默认返回false,View Group中的onInterceptTouchEvent也默认返回false。所以上面5种方案描述出了所有的Touch事件传递可能。了解Touch事件的分发和消费机制,更有利于我们自定义控件,当然我们在自定义控件时,尽量不要重写dispatchTouchEvent这个方法。

本贴参考博客:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html

转载于:https://blog.51cto.com/geektraining/1706171

Android事件流程详解相关推荐

  1. Android事件机制详解

    转自:http://www.codeceo.com/article/android-event.html 1概述 在Android平台上,主要用到两种通信机制,即Binder机制和事件机制,前者用于跨 ...

  2. Android 测量流程详解

    Android  View measure的最终结果是把layout_width和layout_height所设置的相对值转换为具体值的过程.MeasureSpec的种类分为MeasureSpec.E ...

  3. Android App启动流程详解

    前言:在之前的文章中已经写了apk的打包流程.安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程.经过今天的梳理以后咱们就可以对apk包是怎么编译生成的.apk是怎么被安装到安卓手机的 ...

  4. 《Android游戏开发详解》一1.8 控制流程第2部分——while和for循环

    本节书摘来异步社区<Android游戏开发详解>一书中的第1章,第1.8节,译者: 李强 责编: 陈冀康,更多章节内容可以访问云栖社区"异步社区"公众号查看. 1.8 ...

  5. android zygote启动流程,Android zygote启动流程详解

    对zygote的理解 在Android系统中,zygote是一个native进程,是所有应用进程的父进程.而zygote则是Linux系统用户空间的第一个进程--init进程,通过fork的方式创建并 ...

  6. Android SystemUI 架构详解

    Android SystemUI 架构详解 本文描述Android系统中一个核心应用SystemUI,详细赘述SystemUI中几大模块功能的实现过程.由于作者水平有限,如发现本文中错误的地方,欢迎指 ...

  7. Carson带你学Android:图文详解RxJava背压策略

    前言 Rxjava,由于其基于事件流的链式调用.逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎. 本文主要讲解的是RxJava中的 背压控制策略,希望你们会喜欢. Cars ...

  8. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  9. View的绘制-draw流程详解

    目录 作用 根据 measure 测量出的宽高,layout 布局的位置,渲染整个 View 树,将界面呈现出来. 具体分析 以下源码基于版本27 DecorView 的draw 流程 在<Vi ...

最新文章

  1. 学习opengl(起步)
  2. pytest 15 fixture之autouse=True
  3. python中restful接口开发实例_Python RESTful接口开发02
  4. jeecg t:datagrid标签 每页显示条数 扩展
  5. K8S - 为 Docker 而生
  6. 关于PyQt5,在pycharm上的安装步骤及使用技巧
  7. 用ASP+DLL实现WEB方式修改服务器时间
  8. mysql 判断日志时间早_MySQL5.7慢查询日志时间与系统时间差8小时原因详解
  9. Java最全思维导图知识汇总
  10. 华为虚拟专网客户端SecoClient报错“接受返回码超时”故障
  11. 什么是脏数据,缓存中是否可能产生脏数据,如果出现脏数据该怎么处理?
  12. 《陶哲轩实分析》——给读者的一点建议
  13. 原生JS实现弹幕效果
  14. 【Qt】2D基本绘图操作——QPainter执行绘制及绘图设备介绍
  15. -20dB谱宽是什么意思?
  16. 微服务--十个设计要点
  17. 新车被撞折旧费贬值损失怎么算
  18. Arduino Ethernet构建简易服务器
  19. 行内元素、块元素、行内块
  20. 开源配置管理工具config-toolkit 使用心得

热门文章

  1. node js npm 和 cnpm的使用
  2. jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)
  3. 0227windows下模糊查询oracle事件的脚本
  4. MySQL AHI 实现解析
  5. [zz]Apache Thrift学习小记
  6. 独立软件开发商进军SaaS注意八个问题,互联网营销
  7. SmartNIC/DPU — 技术方向
  8. 边缘计算 — 与 AI
  9. C 语言编程 — 头文件
  10. Linux Kernel TCP/IP Stack — L1 Layer — NIC Controller — NAPI