我的编程空间,编程开发者的网络收藏夹
学习永远不晚

老生常谈android中的事件传递和处理机制

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

老生常谈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 View 事件分发机制详解深入解析Android中的事件传递Android事件的分发机制详解详细分析Android中onTouch事件传递机制


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

老生常谈android中的事件传递和处理机制

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

老生常谈android中的事件传递和处理机制

一直以来,都被android中的事件传递和处理机制深深的困扰!今天特意来好好的探讨一下。现在的感觉是,只要你理解到位,其实事件的 传递和处理机制并没有想象中的那么难。总之,不要自己打击自己,要相信自己能掌握这块知识。好了,下面是我今天的收获
2022-06-06

PHP 框架中的事件处理和消息传递机制

php 框架中的事件处理和消息传递机制通过监听特定事件并执行回调函数实现组件间通信。消息传递机制则通过在消息队列中发送和接收消息实现异步处理。实战案例包括用户注册事件、订单处理事件和邮件发送消息,凸显了该机制在构建可扩展、可维护和响应迅速的
PHP 框架中的事件处理和消息传递机制
2024-05-23

C++ 技术中的异常处理:异常传播机制的原理和要点是什么?

异常传播机制:当一个函数发生异常时,它会向上层函数传播,直到被捕获或继续传播。要点:1)异常抛出通过 throw 实现;2)捕获异常使用 try-catch 块;3)重新传播异常使用 rethrow。C++ 异常处理中的异常传播机制:原理和
C++ 技术中的异常处理:异常传播机制的原理和要点是什么?
2024-05-09

Android中自定义view中事件分发机制与处理的示例分析

这篇文章将为大家详细讲解有关Android中自定义view中事件分发机制与处理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。题引事件只有一个,多个人想要处理,处理的对象不是我们想给的对象就是事件
2023-06-25

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录