当前位置:首页>编程日记>正文

Android事件流程详解

Android事件流程详解

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

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

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

    表1:

方法名称功解解说ActivityViewGroupView
dispatchTouchEvent()事件分发YESYESYES
onInterceptTouchEvent()事件拦截NOYESNO
onTouchEvent()事件处理YESYESYES

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


法来分发事件,ActivitydispatchTouchEvent()方法最终会调用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>

Android事件流程详解 配图01


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)
TouchViewGroupfalsesuper.onInterceptTouchEvent(ev)super.onTouchEvent(ev)
TouchViewsuper.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)
TouchViewGrouptruesuper.onInterceptTouchEvent(ev)super.onTouchEvent(ev)
TouchViewsuper.dispatchTouchEvent(ev)----super.onTouchEvent(ev)

运行结果:

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)
TouchViewGroupsuper.onInterceptTouchEvent(ev)truesuper.onTouchEvent(ev)
TouchViewsuper.dispatchTouchEvent(ev)----super.onTouchEvent(ev)

运行结果:

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

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

结果分析: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)
TouchViewGroupsuper.onInterceptTouchEvent(ev)falsesuper.onTouchEvent(ev)
TouchViewsuper.dispatchTouchEvent(ev)----super.onTouchEvent(ev)


运行结果:

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

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

结果分析: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)
TouchViewGroupsuper.onInterceptTouchEvent(ev)falsesuper.onTouchEvent(ev)
TouchViewtrue----super.onTouchEvent(ev)


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


http://www.coolblog.cn/news/e1fd180d942b8479.html

相关文章:

  • asp多表查询并显示_SpringBoot系列(五):SpringBoot整合Mybatis实现多表关联查询
  • s7day2学习记录
  • 【求锤得锤的故事】Redis锁从面试连环炮聊到神仙打架。
  • 矿Spring入门Demo
  • 拼音怎么写_老师:不会写的字用圈代替,看到孩子试卷,网友:人才
  • Linux 实时流量监测(iptraf中文图解)
  • Win10 + Python + GPU版MXNet + VS2015 + RTools + R配置
  • 美颜
  • shell访问php文件夹,Shell获取某目录下所有文件夹的名称
  • 如何优雅的实现 Spring Boot 接口参数加密解密?
  • LeCun亲授的深度学习入门课:从飞行器的发明到卷积神经网络
  • Mac原生Terminal快速登录ssh
  • java受保护的数据与_Javascript类定义语法,私有成员、受保护成员、静态成员等介绍...
  • mysql commit 机制_1024MySQL事物提交机制
  • 支撑微博千亿调用的轻量级RPC框架:Motan
  • jquery 使用小技巧
  • 2019-9
  • 法拉利虚拟学院2010 服务器,法拉利虚拟学院2010
  • vscode pylint 错误_将实际未错误的py库添加到pylint白名单
  • 科学计算工具NumPy(3):ndarray的元素处理
  • 工程师在工作电脑存 64G 不雅文件,被公司开除后索赔 41 万,结果…
  • linux批量创建用户和密码
  • newinsets用法java_Java XYPlot.setInsets方法代碼示例
  • js常用阻止冒泡事件
  • 气泡图在开源监控工具中的应用效果
  • 各类型土地利用图例_划重点!国土空间总体规划——土地利用
  • php 启动服务器监听
  • dubbo简单示例
  • 【设计模式】 模式PK:策略模式VS状态模式
  • [iptables]Redhat 7.2下使用iptables实现NAT
  • Ubuntu13.10:[3]如何开启SSH SERVER服务
  • CSS小技巧——CSS滚动条美化
  • JS实现-页面数据无限加载
  • 阿里巴巴分布式服务框架 Dubbo
  • 最新DOS大全
  • Django View(视图系统)
  • 阿里大鱼.net core 发送短信
  • 程序员入错行怎么办?
  • 两张超级大表join优化
  • 第九天函数
  • Linux软件安装-----apache安装
  • HDU 5988 最小费用流
  • Sorenson Capital:值得投资的 5 种 AI 技术
  • 《看透springmvc源码分析与实践》读书笔记一
  • 正式开课!如何学习相机模型与标定?(单目+双目+鱼眼+深度相机)
  • Arm芯片的新革命在缓缓上演
  • nagios自写插件—check_file
  • python3 错误 Max retries exceeded with url 解决方法
  • 行为模式之Template Method模式
  • 通过Spark进行ALS离线和Stream实时推荐