android中的事件传递和处理机制
一直以来,都被android中的事件传递和处理机制深深的困扰!今天特意来好好的探讨一下。现在的感觉是,只要你理解到位,其实事件的
传递和处理机制并没有想象中的那么难。总之,不要自己打击自己,要相信自己能掌握这块知识。好了,下面是我今天的收获,希望也
能对你有一点帮助。
一、拟人化来理解android中的事件机制
其实android中的事件传递与处理机制跟我们生活中的事件处理是一样的。这里有一个生活中的例子,很能说明这个问题。阐述如下:
你是一个公司的员工,你的上头有一个主管,主管上头呢还有一个经理。为了简单,你们这个团队就有这三个人。那么如果上头安排一件事下来要处理,流程是怎样的呢?
显然应该是由你的经理将这件事安排给你的主管来处理,你的主管再将这件事安排给你来处理。等你把这件事办好了,你就应该给你的主管报告,再由你的主管来向你的经理
报告。显然,你的主管和经理也有处理这件事的权限,如果他们觉得事情很复杂,你办不了,或者他们比较照顾下级,可能就自己把这件事给办了,这个时候这件事就不会再
传递给下一级来处理了。这个事件处理的过程,是不是太容易理解了!
其实android中的事件处理流程就是跟生活中的事件处理是一样的。比如你在ViewGroupA中嵌套了一个VewiGroupB,然后又在ViewGroupB
中嵌套了一个MyView。那么一个触摸事件传递过来,会发生什么情况呢?类比上面的公司员工的处理事件,显然会发生下面的过程:
触摸事件传递过来后,ViewGroupA一看自己里面还有一个员工可以利用,就是ViewGroupB,那不用白不用,就会把这个事件传递给ViewGroupB,告诉他,你给我把这个事件处理了!
ViewGroupB呢一看,我不怕,我里面也有一个员工就是MyView,它得给我干活,于是又会把这个事件传递给MyView,让它来处理。MyView一看,没办法啊,我手底下没有员工了,那
怎么办,我只能自己处理了(前提是它有处理这个事件的能力),所以就把这个触摸事件给处理了。处理完成后呢?MyView就是给ViewGroupB报告,我已经把事情办好了,你来审核一下
,看看办理的咋样。ViewGroupB一审核,觉得不错,就再将结果呈现给ViewGroupA。ViewGroupA再审核,通过了才算通过。在这个过程中,也可能出现几种情况:
(1)MyView说,完蛋了,这事我的能力办不好啊,于是就向VeiwGroupB报告,我没有处理,请你来处理,你是我上司,能力比我强。于是ViewGroupB就会来帮忙处理。当然了,
如果ViewGroupB也没能力处理,那就只能反馈给VeiwGroupA,让它来消化这个事件。
(2)也可能MyView处理非常完美,向ViewGroupB一报告,ViewGroupB一开心就说不用再交给ViewGroupA审核了,我担保通过,于是事件到此直接终止。
上面用很形象的话来讲adnroid中的事件传递和处理机制讲解了一下。android用下面的几个方法将上面的过程完美封装了:
在ViewGroup中,有下面三个方法:
(1)dispatchTouchEvent 该方法用来分发事件,一般不会重写这个方法
(2)onInterceptTouchEvent 用来拦截事件
(3)onTouchEvent 用来处理事件,这个方法应该大家很常见了吧 而View中,只有两个方法,即:
(1)dispatchTouchEvent 该方法用来分发事件,一般不会重写这个方法
(2)onTouchEvent 用来处理事件,这个方法应该大家很常见了吧
那么我们就来写一个实际的代码,来验证一下这些方法都对应上面的哪些过程。这样子就会对这个些方法有更透彻的理解。
二、根据实战代码来分析各个方法
下面我们就来把上面提到的ViewGroupA,ViewGroupB,还有MyView给编写出来。
新建一个项目,先来写ViewGruopA,代码如下:
package com.example.testmotionevent; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout; public class ViewGroupA extends LinearLayout{ public ViewGroupA(Context context) {
super(context);
}
public ViewGroupA(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupA(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("付勇焜----->","ViewGroupA dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d("付勇焜----->","ViewGroupA onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("付勇焜----->","ViewGroupA onTouchEvent");
return super.onTouchEvent(event);
}
}
代码很简单,就不用我解释了吧,无非就是重写上面提到的那几个方法,然后打印相关的标记,来观察事件的处理机制。
同理,编写ViewGroupB,如下:
package com.example.testmotionevent; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout; public class ViewGroupB extends LinearLayout{ public ViewGroupB(Context context) {
super(context);
}
public ViewGroupB(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupB(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("付勇焜----->","ViewGroupB dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d("付勇焜----->","ViewGroupB onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("付勇焜----->","ViewGroupB onTouchEvent");
return super.onTouchEvent(event);
}
}
然后再编写MyView,如下:
package com.example.testmotionevent; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View; public class MyView extends View{ public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} @Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("付勇焜---->","MyView dispatchTouchEvent ");
return super.dispatchTouchEvent(event);
} @Override
public boolean onTouchEvent(MotionEvent event) { Log.d("付勇焜---->","MyView onTouchEvent ");
return super.onTouchEvent(event);
}
}
好了,现在就将它们嵌套在一起,修改activity_main.xml,如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
> <com.example.testmotionevent.ViewGroupA
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#ff0033">
<com.example.testmotionevent.ViewGroupB
android:layout_width="200dp"
android:layout_height="200dp"
android:gravity="center"
android:background="#336699">
<com.example.testmotionevent.MyView
android:layout_width="100dp"
android:layout_height="100dp"
android:clickable="true"
android:background="#ffff00"/> </com.example.testmotionevent.ViewGroupB> </com.example.testmotionevent.ViewGroupA> </LinearLayout>
嵌套完成,运行程序,是什么样子的呢?如下图:

红色的就是ViewGroupA,蓝色的就是ViewGroupB,黄色就是MyView。现在来点击中间黄色的MyView,观察下打印结果,如下:

从打印的结果,我们可以很清楚到看到事件的流程:
首先ViewGroupA得到了事件,由它的dispatchTouchEvent方法来分发事件,由于它的onInterceptTouchEvent方法没有做出拦截,因此事件传递给了ViewGroupB,
而同样由于ViewGroupB的onInterceptTouchEvent方法在它的dispatchTouchEvent方法分发事件时没有做出拦截,故而事件最终被传递给MyView,MyView就来处理这个
事件了。
下面我们来做实验吧,我们让MyView没有处理这个事件,会是上面我们所说的由ViewGrouPB来处理吗?修改MyView的onTouchEvent事件,如下:
public boolean onTouchEvent(MotionEvent event) {
Log.d("付勇焜---->","MyView onTouchEvent ");
return false;
// return super.onTouchEvent(event);
}
我们return了false,表示MyView没有成功处理这个事件。现在来再运行下程序,打印结果如下:

由于MyView的onTouchEvent返回false,因此事件就交给了它的上级ViewGroupB来处理,于是ViewGroupB的onTouchEvent就来消化这个事件了。所以
从打印的结果来看正是这个情况(即红色线条标注的部分)。但是由于ViewGroupB的onTouchEvent也没有成功处理这个事件所以又传递给ViewGroupA的
onToucEvent来处理这个事件(即红色线最下面还有ViewGroupA的标志)。不管ViewGroupA能不能成功处理,我们的程序中它是终极boss,不会再由其他对象
来处理该事件了。
再来在上一步的基础上继续做实验。当MyView没有成功处理事件,传递给ViewGroupB来处理时,当ViewGroupB处理完,我们强制告知程序,ViewGroupB
已经成功处理该事件了,看看会出现什么情况!修改ViewGroupB的onTouchEvent代码,如下:
public boolean onTouchEvent(MotionEvent event) {
Log.d("付勇焜----->","ViewGroupB onTouchEvent");
return true; //表示事件已经成功处理
// return super.onTouchEvent(event);
}
再来运行程序,观察打印结果如下:

观察红线部分,此时只剩下ViewGroupB的onTouchEvent了。因为ViewGroupB已经成功处理这事件了,那就不必再劳烦ViewGroupA来吃处理了。
好了,现在我们在上一个实验的基础上再来实验。比如,当事件传递到ViewGroupB的时候,ViewGroupB比较好心,心想干脆我来处理这个事情吧,就不必再让MyView
加班了,于是他对这个事件进行了拦截!修改ViewGroupB的onInterceptTouchEvent代码,如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d("付勇焜----->","ViewGroupB onInterceptTouchEvent");
return true;
// return super.onInterceptTouchEvent(ev);
}
再次运行程序,观察打印结果,如下:

我们发现事件传递到ViewGroupB的地方直接终止了,然后就是ViewGroupB的onTouchEvent事件来处理了,当然了因为之前我们强制修改ViewGroupB的onTouchEvent
为处理成功,因此也不会再返回给ViewGroupA的onTouchEvent来处理了。此时MyView压根就不知道有个触摸事件在它的上层传递呢!所以在打印结果中,我们连MyView的影子
都见不到!
好了,我就带大家做这几个实验吧。已经足够说明问题了。下面我们就来做一下总概述吧。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
从上面的实验我们可以很清晰的看到一个事件处理的流程,在正常情况下,是如下图的这样子的一个流程:

也就是说,一个事件是必须要先经过传递流程才会再经过处理流程。这个先后顺序一定要明白。如果你无法理解,请再想一想上面拟人化的公司员工处理事件的流程吧。
其中,在红色线和蓝色线代表传递的流程中,我们都可以进行所谓的拦截事件。说明如下:
对于事件的拦截,我们主要重写就是OnInterceptTouchEvent和onTouchEvent方法。两句就可以总结:
(1)对于事件的传递,返回结果为true,表示拦截,不再往下传递,为false,不拦截,继续往下传递。主要针对的就是OnInterceptTouchEvent方法。
(2)对于事件的处理,返回结果为true,表示拦截,不再往上传递(即我处理的很完美,不需要你再来审核我!),返回结果为false(没有成功处理事件),继续向上传递。
针对就是onTouchEvent方法。
因此我们就可以通过控制OnInterceptTouchEvent和onTouchEvent方法的返回值来控制整个事件的传递流程和处理流程!!到此,你是不是对andorid中的事件的整个处理机制很
明白了呢?以后再出现什么问题,是不是就可以顺藤摸瓜,找到问题所在了!
三、总结
如果你嫌上面的解释太啰嗦了。那么就只看下面的这个总结就可以了,一下就找到关键的知识点!如下:
(1)正常情况下,android中的事件是必须要经过传递流程然后再经过处理流程的。要记住这个先后的顺序。 (2)在传递流程和处理流程中,你都可以修改方法的返回值,来对流程做控制。如下:
对于事件的拦截,我们主要重写就是OnInterceptTouchEvent和onTouchEvent方法。两句就可以总结:
事件的传递,返回结果为true,表示拦截,不再往下传递,为false,不拦截,继续往下传递。主要针对的就是OnInterceptTouchEvent方法。
事件的处理,返回结果为true,表示拦截,不再往上传递(即我处理的很完美,不需要你再来审核我!),返回结果为false(没有成功处理事件),继续向上传递。
针对就是onTouchEvent方法。
(3)如果流程你还理解,就好好想一想那个公司员工的拟人化解释吧!实际上android的事件处理机制原理就是这样子的!
android中的事件传递和处理机制的更多相关文章
- Android中的事件传递机制
Android源码版本:API Level 19(Android 4.4) Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和 ...
- Android中的事件分发机制
Android中的事件分发机制 作者:丁明祥 邮箱:2780087178@qq.com 这篇文章这周之内尽量写完 参考资料: Android事件分发机制完全解析,带你从源码的角度彻底理解(上) And ...
- 一个demo让你彻底理解Android中触摸事件的分发
注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOW ...
- Xamarin Android 中Acitvity如何传递数据
在xamarin android的开发中,activity传递数据非常常见,下面我也来记一下在android中activity之间传递数据的几种方式, Xamarin Android中Activity ...
- 浅谈Android中的事件分发机制
View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...
- zigbee 中 OSAL 事件传递机制和消息传递机制
一.概述 OSAL (Operating System Abstraction Layer) ,翻译为"操作系统抽象层". OSAL 就是一种支持多任务运行的系统资源分配机制.OS ...
- 【转】Android中的事件分发和处理
原文链接:http://www.apkbus.com/home.php?mod=space&uid=705730&do=blog&id=61207 上次跟大家分享了一下自定义V ...
- Android中callback(接口回调)机制
事实上,callback 机制在Android 中无处不在,特别是以Handler.Callback.Listener这三个词结尾的,都是利用callback机制来实现的.比方点击事件onClickL ...
- Android 手机卫士--事件传递&响应规则
问题的提出: 本文地址:http://www.cnblogs.com/wuyudong/p/5911187.html ,转载请注明源地址. 前面的文章实现了点击SettingItemView条目的时候 ...
随机推荐
- JAVA生成随机数种子的方法
Java里面有一个随机函数——Random,刚开始只是知道这个函数具有随机取值的作用,于是上网搜索了资料一番,做了一下一些关于Random函数的总结: Java中存在着两种Random函数: 一. ...
- Android、iOS和Windows Phone中的推送技术
推送并不是什么新技术,这种技术在互联网时代就已经很流行了.只是随着进入移动互联网时代,推送技术显得更加重要.因为在智能手机中,推送从某种程度上,可以取代使用多年的短信,而且与短信相比,还可以向用户展示 ...
- JavaScript 的数据类型 相关知识点
(1)基本数据类型介绍 JavaScript的数据类型分为两类:原始类型(primitive type)和对象类型(object type) 或者说是:可以拥有方法的类型和不能拥有方法的类型 或者说是 ...
- 计算html标签textarea字符长度
今天学习jQuery,做练习计算html标签textarea字符长度,先添加一个视图操作(Action): 创建一个视图,并按下面顺序标记1,2,3进行写html或javascript脚本: 其中标记 ...
- eclipse中改变默认的workspace的方法及说明
eclipse中改变默然的workspace的方法可以有: 1.在创建project的时候,手动选择使用新的workspace,如创建一个web project,在向导中的Location选项,取消使 ...
- 混合式APP开发中中间件方案Rexsee
发现Rexsee时,他已经一年多没有更新过了,最后版本是2012年的. 他的实现思路是通过Android自带的Java - Javascript 桥机制,在WebView中的JavaScript同Ja ...
- kfreebsd不适用于实际环境
debian搞的kfreebsd,其中有很多常用的软件包处于依赖破损的状态,个人觉得是无法用作日常开发或生产环境的. 当然,对于只使用其中几项完整可用功能的场景,基本上还是可以的. 当时看个这个东东的 ...
- 在MVC中应用百度富文本编辑器
1.下载.NET版本的百度富文本编辑器,前往 下载.NET版本百度富文本框 2.解压下载的.zip压缩包,将utf8-.net文件夹名称改为:ueditor,复制到MVC根目录下面.结构如下: App ...
- android开发布局文件imageview 图片等比例缩放:
ImageView的属性scaleType,如果等比缩放的话,就使用CenterInside,如果想固定大小的话,就CenterCrop <?xml version="1.0" ...
- XML的介绍
XML是指可扩展标记语言(eXtensible Markup Language),它是一种标记语言,类似于HTML.它被设计的宗旨是传输数据,而非显示数据. XML标签没有被预定义,需要开发者自定 ...