Android onTouchEvent, onClick及onLongClick的调用机制

针对屏幕上的一个View控件,Android如何区分应当触发onTouchEvent,还是onClick,亦或是onLongClick事件?

在Android中,一次用户操作可以被不同的View按次序分别处理,并将完全响应了用户一次UI操作称之为消费了该事件(consume),那么Android是按什么次序将事件传递的呢?又在什么情况下判定为消费了该事件?

搞清楚这些问题对于编写出能正确响应UI操作的代码是很重要的,尤其当屏幕上的不同View需要针对此次UI操作做出各种不同响应的时候更是如此,一个 典型例子就是用户在桌面上放置了一个Widget,那么当用户针对widget做各种操作时,桌面本身有的时候要对用户的操作做出响应,有时忽略。只有搞 清楚事件触发和传递的机制才有可能保证在界面布局非常复杂的情况下,UI控件仍然能正确响应用户操作。

1.  onTouchEvent

onTouchEvent中要处理的最常用的3个事件就是:ACTION_DOWN、ACTION_MOVE、ACTION_UP。

这三个事件标识出了最基本的用户触摸屏幕的操作,含义也 很清楚。虽然大家天天都在用它们,但是有一点请留意,ACTION_DOWN事件作为起始事件,它的重要性是要超过ACTION_MOVE和 ACTION_UP的,如果发生了ACTION_MOVE或者ACTION_UP,那么一定曾经发生了ACTION_DOWN。

从Android的源代码中能看到基于这种不同重要性的理解而实现的一些交互机制,SDK中也有明确的提及,例如在ViewGroup的 onInterceptTouchEvent方法中,如果在ACTION_DOWN事件中返回了true,那么后续的事件将直接发给 onTouchEvent,而不是继续发给onInterceptTouchEvent。

2.  onClick、onLongClick与onTouchEvent

曾经看过一篇帖子提到,如果在View中处理了onTouchEvent,那么就不用再处理onClick了,因为Android只会触发其中一个方 法。这个理解是不太正确的,针对某个view,用户完成了一次触碰操作,显然从传感器上得到的信号是手指按下和抬起两个操作,我们可以理解为一次 Click,也可以理解为发生了一次ACTION_DOWN和ACTION_UP,那么Android是如何理解和处理的呢?

在Android中,onClick、onLongClick的触发是和ACTION_DOWN及ACTION_UP相关的,在时序上,如果我们在一 个View中同时覆写了onClick、onLongClick及onTouchEvent的话,onTouchEvent是最先捕捉到 ACTION_DOWN和ACTION_UP事件的,其次才可能触发onClick或者onLongClick。主要的逻辑在View.java中的 onTouchEvent方法中实现的:

case MotionEvent.ACTION_DOWN:

mPrivateFlags |= PRESSED;

refreshDrawableState();

if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {

postCheckForLongClick();

break;

case MotionEvent.ACTION_UP:

if ((mPrivateFlags & PRESSED) != 0) {

boolean focusTaken = false;

if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {

focusTaken = requestFocus();

if (!mHasPerformedLongPress) {

if (mPendingCheckForLongPress != null) {

removeCallbacks(mPendingCheckForLongPress);

if (!focusTaken) {

performClick();

break;

可以看到,Click的触发是在系统捕捉到ACTION_UP后发生并由performClick()执行的,performClick里会调用先前注册的监听器的onClick()方法:

public boolean performClick() {

if (mOnClickListener != null) {

playSoundEffect(SoundEffectConstants.CLICK);

mOnClickListener.onClick(this);

return true;

return false;

LongClick的触发则是从ACTION_DOWN开始,由postCheckForLongClick()方法完成:

private void postCheckForLongClick() {

mHasPerformedLongPress = false;

if (mPendingCheckForLongPress == null) {

mPendingCheckForLongPress = new CheckForLongPress();

mPendingCheckForLongPress.rememberWindowAttachCount();

postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());

可以看到,在ACTION_DOWN事件被捕捉后,系统会开始触发一个postDelayed操作,delay的时间在Eclair2.1上为500ms,500ms后会触发CheckForLongPress线程的执行:

class CheckForLongPress implements Runnable {

public void run() {

if (isPressed() && (mParent != null)

&& mOriginalWindowAttachCount == mWindowAttachCount) {

if (performLongClick()) {

mHasPerformedLongPress = true;

如果各种条件都满足,那么在CheckForLongPress中执行performLongClick(),在这个方法中将调用onLongClick():

public boolean performLongClick() {

if (mOnLongClickListener != null) {

handled = mOnLongClickListener.onLongClick(View.this);

从实现中可以看到onClick()和onLongClick()方法是由ACTION_DOWN和ACTION_UP事件捕捉后根据各种情况最终确定是 否触发的,也就是说如果我们在一个Activity或者View中同时监听或者覆写了onClick(),onLongClick()和 onTouchEvent()方法,并不意味着只会发生其中一种。

下面是一个onClick被触发的基本时序的Log:

04-05 05:57:47.123: DEBUG/TSActivity(209): onTouch ACTION_DOWN

04-05 05:57:47.263: DEBUG/TSActivity(209): onTouch ACTION_UP

04-05 05:57:47.323: DEBUG/TSActivity(209): onClick

可以看出是按ACTION_DOWN -> ACTION_UP -> onClick的次序发生的。

下面是一个onLongClick被触发的基本时序的Log:

04-05 06:00:04.133: DEBUG/TSActivity(248): onTouch ACTION_DOWN

04-05 06:00:04.642: DEBUG/TSActivity(248): onLongClick

04-05 06:00:05.083: DEBUG/TSActivity(248): onTouch ACTION_UP

可以看到,在保持按下的状态一定时间后会触发onLongClick,之后抬起手才会发生ACTION_UP。

3.  onClick和onLongClick能同时发生吗?

要弄清楚这个问题只要理解Android对事件处理的所谓消费(consume)概念即可,一个用户的操作会被传递到不同的View控件和同一个控件 的不同监听方法处理,任何一个接收并处理了该次事件的方法如果在处理完后返回了true,那么该次event就算被完全处理了,其他的View或者监听方 法就不会再有机会处理该event了。

onLongClick的发生是由单独的线程完成的,并且在ACTION_UP之前,而onClick的发生是在ACTION_UP后,因此同一次用 户touch操作就有可能既发生onLongClick又发生onClick。这样是不是不可思议?所以及时向系统表示“我已经完全处理(消费)了用户的 此次操作”,是很重要的事情。例如,我们如果在onLongClick()方法的最后return true,那么onClick事件就没有机会被触发了。

下面的Log是在onLongClick()方法return false的情况下,一次触碰操作的基本时序:

04-05 06:00:53.023: DEBUG/TSActivity(277): onTouch ACTION_DOWN

04-05 06:00:53.533: DEBUG/TSActivity(277): onLongClick

04-05 06:00:55.603: DEBUG/TSActivity(277): onTouch ACTION_UP

04-05 06:00:55.663: DEBUG/TSActivity(277): onClick

可以看到,在ACTION_UP后仍然触发了onClick()方法。

时间: 2024-10-28 16:17:30

Android onTouchEvent, onClick及onLongClick的调用机制的相关文章

Android中onTouchEvent, onClick及onLongClick的调用机制(二)

android应用中常用的监听OnTouchListener.OnClickListener.OnLongClickListener,大家肯定经常使用.但是你真的知道它会产生的神奇效果么?不要忽视这些神奇效果哦!说不定这些神奇效果正是你想要的呢?好,下面请看我的示例. 示例. 首先在Activity中创建一个button,然后对这个button同时设置OnTouchListener.OnClickListener.onLongClickListener这三种监听方式.接着就是重写这三个接口的实现

Android OnTouchEvent, onClick, onLongClick调用机制

在Android开发中,我们经常会对一个View设置onClick,onLongClick,onTouch事件,有时还会同时设置这三个事件,那么在同时设置这三个时候,执行顺序是什么样呢? 首先,官方文档上面对onLongClick()和onTouch()的描述如下: onLongClick() - This returns a boolean to indicate whether you have consumed the event and it should not be carried

Android View 按键事件分发流程 onTouch onTouchEvent onClick onLongClick 和 onKey onKeyDown onClick

1.为了测试,我们同时将View 设置 onTouch  onTouchEvent  onClick onLongClick 四个事件,经过加打印测试发现,按键分发流程是这样的 如果是短按:onTouch-->>onTouchEvent--->>onClick .长按:onTouch-->>onTouchEvent--->>onLongClick-->>onClick.为什么会是这样? 我们看View 源码 public boolean disp

浅谈Android onClick与onLongClick事件触发的问题

之前做按钮的点击事件一直没有注意一些细节,今天做了一个按钮需要有点击和长点击触发不同效果,直接让Activity implements OnClickListener, OnLongClickListener然后添加了相应的处理函数. @Override public void onClick(View v) { // TODO Auto-generated method stub } @Override public boolean onLongClick(View v) { // TODO

android内核剖析系列---JNI调用机制分析

为什么需要JNI? android这个庞大的系统从下到上主要由linux内核,C/C++库,java应用程序框架,java应用程序组成.这就涉及到一个问题,C/C++库如何与java应用有交集,或者说能相互调用,要解决这个问题,就需要JNI登场了. JNI调用机制分析 JNI--java native interface,翻译成中文是java本地接口,所谓的"本地"是指C/C++库一层的C/C++语言(以下统称C).

Android系统篇之----解读AMS远端服务调用机制以及Activity的启动流程

一.为何本文不介绍Hook系统的AMS服务 在之前一篇文章中已经讲解了 Android中Hook系统服务,以及拦截具体方法的功能了,按照流程本文应该介绍如何Hook系统的AMS服务拦截应用的启动流程操作,但是本文并不会,因为在介绍这个知识点之前,还有一件大事要做,那就是得先分析一下Android中应用的启动流程,如果这个流程不搞清楚的话,后面没办法Hook的,因为你都找不到Hook点,当然Hook代理对象倒是很容易获得,如果没有Hook点,是没办法后续的操作的,所以得先把流程分析清楚了,当然现在

Android系统篇之----Binder机制和远程服务调用机制分析

一.前景概要 最近要实现Android中免注册Activity就可以运行的问题,那么结果是搞定了,就是可以不用在AndroidManifest.xml中声明这个Activity即可运行,主要是通过骗取系统,偷龙转凤技术的,这个知识点后面会详细讲解的,因为在研究了这个问题过程中遇到了很多知识点,当然最重要也是最根本的就是Android中的Binder机制和远程服务调用机制,而关于Binder机制的话,在Android中算是一个非常大的系统架构模块了,光这篇文章是肯定不能讲解到全部的,而且本人也不是

如何在android平台上使用js直接调用Java方法[转]

转载自:http://www.cocos.com/docs/html5/v3/reflection/zh.html #如何在android平台上使用js直接调用Java方法 在cocos2d-js 3.0beta中加入了一个新特性,在android平台上我们可以通过反射直接在js中调用java的静态方法.它的使用方法很简单: var o = jsb.reflection.callStaticMethod(className, methodName, methodSignature, parame

android中的事件传递和处理机制

一直以来,都被android中的事件传递和处理机制深深的困扰!今天特意来好好的探讨一下.现在的感觉是,只要你理解到位,其实事件的 传递和处理机制并没有想象中的那么难.总之,不要自己打击自己,要相信自己能掌握这块知识.好了,下面是我今天的收获,希望也 能对你有一点帮助. 一.拟人化来理解android中的事件机制 其实android中的事件传递与处理机制跟我们生活中的事件处理是一样的.这里有一个生活中的例子,很能说明这个问题.阐述如下: 你是一个公司的员工,你的上头有一个主管,主管上头呢还有一个经