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.TouchViewGroup
    xmlns: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.TouchView
            android: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

时间: 2025-01-02 01:53:53

Android事件流程详解的相关文章

Android事件分发详解(五)——Touch事件传递验证

MainActivity如下: package cn.c; import android.os.Bundle; import android.app.Activity; import android.view.MotionEvent; /** * Demo描述: * 分析Android事件分发和处理机制 * * * 总结: * 1 ViewGroup继承自View * 事件的传递方向为:从最外层(Activity)传递至最内层(某个View) * 事件的消费方向为:从最内层(某个View)传递至

Android事件分发详解(六)——ACTION_DOWN的消费验证

MainActivity如下: package cn.c; import android.os.Bundle; import android.app.Activity; import android.view.MotionEvent; /** * Demo描述: * 分析Android事件分发和处理机制 * * 在该示例中涉及到三个自定义的View.分别是: * 最外层的布局MyFrameLayout * 内层的布局MyLinearLayout * 最里层的自定义按钮MyButton * * 在

Android事件分发详解(四)——事件传递基础示例

MainActivity如下: package com.cn; import android.app.Activity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; /** * Demo描述: * Andr

Android事件分发详解(三)——ViewGroup的dispatchTouchEvent()源码学习

package cc.aa; import android.os.Environment; import android.view.MotionEvent; import android.view.View; public class UnderstandDispatchTouchEvent { /** * dispatchTouchEvent()源码学习及其注释 * 常说事件传递中的流程是:dispatchTouchEvent->onInterceptTouchEvent->onTouchE

Android事件分发详解(一)——View的事件分发

MainActivity如下: package cc.cv; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.Button; import android.widge

Android事件机制详解

TouchEvent事件研究 1.          Activity事件分析   dispatchTouchEvent onTouchEvent 执行结果 1 Super Super dispatchTouchEvent à onTouchEvent 2 false dispatchTouchEvent 3 true 2.          View and Activity事件分析 Activity view 执行结果 dispatchTouchEvent(1) onTouchEvent(2

Android4.0 input事件输入流程详解(中间层到应用层)

在Android系统中,类似于键盘按键.触摸屏等事件是由WindowManagerService服务来管理的,然后再以消息的形式来分发给应用程序进行处理.系统启动时,窗口管理服务也会启动,该服务启动过程中,会通过系统输入管理器InputManager来负责监控键盘消息.当某一个Activity激活时,会在该Service下注册一个接收消息的通道,表明可以处理具体的消息,然后当有消息时,InputManager就会分发给当前处于激活状态下的Activity进行处理. InputManager的启动

unity3d-配置Android环境,打包发布Apk流程详解

31:unity3d-配置Android环境,打包发布Apk流程详解 作者 阿西纳尼 关注 2016.08.28 22:52 字数 498 阅读 1806评论 0喜欢 5 Unity配置Android环境,打包发布安卓流程 一:SDK与JDK下载地址:http://pan.baidu.com/s/1mhVaXHe下载完成后,解压文件 SDK文件 二.安装 JDK 运行安装程序jdk-7u67-windows-x64 Java-JDK 分别点击下一步进行安装. 安装中 在安装过程中先后会出现两次选

Android Touch事件分发详解

Android Touch事件分发详解 先说一些基本的知识,方便后面分析源码时能更好理解. - 所有Touch事件都被封装成MotionEvent对象,包括Touch的位置.历史记录.第几个手指等. 事件类型分为ACTION_DOWN,ACTION_UP,ACTION_MOVE,ACTION_POINTER_DOWN,ACTION_POINTER_UP,ACTION_CANCEL, 每个 一个完整的事件以ACTION_DOWN开始ACTION_UP结束,并且ACTION_CANCEL只能由代码引