Android_事件纷发

关于事件你应该知道的是

当一个事件产生后,他的传递过程遵循如下顺序Activity > Window > View

事件来源于activity,activity假如你没有重写任何关于事件纷发的方法的话,他会把事件传递给window,window将事件传递给decorView

现在我们来看下假如我们在activity中重写了dispatchEvent的方法是什么样的一个情况.

  1. 我们把activity中的dispatchTouchEvent 返回true

    事件被activity的dispatchTouchEvent消耗掉,所以activity的

    onTouchEvent方法得不到响应,我们看下log输出

    很明显的能看出来,log只打印了dispatchTouchEvent中的相关方法,整个事件被dispatchTouchEvent消耗掉,并没有传递到我们的window > decorView 所有我界面的返回键接受不到事件,所以返回按钮的点击事件也没生效,

  2. 我们在把activity中的dispatchTouchEvent返回false看看是什么情况,,这也是我的一个疑问点,麻烦大神帮忙解答一下就是我activity中的dispatchTouchEvent返回了false,那么事件标志着事件没人处理,此时事件的根源是从activity来的,如果他都不管的话,这个事件已经不能返回他的父view ,当前activity的onTouchEvent()也无log输出,那么事件哪里去了????

    然后我们看下返回false的log输出如下图:

    log输出一只执行了activity中的dispatchTouchEvent的相关方法,

    TouchEvent并没有任何输出,表明activity的onTouchEvent也没有接受到这个事件,此时我再点击返回键,的onclick依然是失效的,

    所以.麻烦大神帮忙解答下这一点,当activity中的dispatchtouchevent返回false,事件的流程是怎么样的,???

  3. 最后我们让activity中的dispatchtouchevent 返回super看下

    然后看下log日志的输出,以及log 的顺序,

注意log的顺序,dispatchTouchEvent down > onTouchEvent down

dispatchTouchEvent move > onTouchEvent move

dispatchTouchEvent up > onTouchEvent up

面试的时候注意面试官问的问题,和执行顺序的问题

  • 然后我们往activity中加入一个linearlayout,我们重写一下linearlayout的有关事件的三个方法,并打印log看一下,暂时不往linearlayout中加入任何子view,单纯的看一下事件从activity传递到viewgroup的效果.

    首先我们在书写一个TESTLinearlayout,如下

public class AAATestLinearlayout extends LinearLayout {
    private static final String TAG = "AAATestLinearlayout";

    public AAATestLinearlayout(Context context) {
        super(context);
    }

    public AAATestLinearlayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AAATestLinearlayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Logger.e(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logger.d(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logger.w(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_UP");
                break;
        }

//        return true;
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Logger.e(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logger.d(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logger.w(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_UP");
                break;
        }

//        return true;
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Logger.e(TAG, TAG + ">>>>onTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logger.d(TAG, TAG + ">>>>onTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logger.w(TAG, TAG + ">>>>onTouchEvent.ACTION_UP");
                break;
        }

        return super.onTouchEvent(event);
    }

}

我们就先默认的让测试的linearlayout全部返回super值.

看下事件传递的过程从activity > window > decorView > 我们自己的linearlayout;

并且我们在linearlayout中的构造中设置了额外的onTouchLinstener,

我们看下的结果;

这里简答描述一下,我们往activity中加入了一个linearlayout.并且在构造中给linearlayoutset了一个touchlistener.

我们从log可以看到,事件从activity中开始传递,然后我们在linearlayout中有关事件的方法全部返回super.

其中关于onInterceptTouchEvent

我想说两句,这句话的返回值影响的是viewgroup容器中子view的事件传递,并不会对当前的viewgroup的onTouchEvent或者set 的touchlistener有影响,我们从log可以看出来,linearlayout的 onTouchEvent.down 和 touchliste的down均执行了

假如onInterceptTouchEvent的值返回的是super的话,我们看viewgroup的源码可以知道

默认是false,也就是不拦截…重要的是不拦截….

    * appear here.
     * </ol>
     *
     * @param ev The motion event being dispatched down the hierarchy.
     * @return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.
     */
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }

这是viewgroup的源码,和Android艺术探索第143页第六条说的完全吻合,

还有一篇博客,应该是比较经典的,其中对onInterceptTouchEvent的解释如下;

这里博客博主说是返回super的话默认被拦截,并把拦截的事件交给当前view,处理,

我们这里的当前view就是我们的linearlayoutlayout 从log看确实执行了onTouchEvent.但是这个onTouchEvent并不是因为返回了super他没有拦截而执行了.因为笔者试着返回true false,super,对我们设置的touchlistener和onTouchEvent的down事件没有任何影响,

所以这块我也迷茫了半天,看了书本和咨询了群里的nil大概猜测一下可能是博主理解有出入或者笔误,再次留下博客的地址:请大神批阅和校正一下原文链接如下Android编程下的事件纷发

接着说我们的场景,目前我们linearlayout中的事件处理方法均没有对事件做处理,这样我们linearlayout中的子view比如我们的返回按钮确实能接收到事件,然后点击返回箭头,activity关闭,此事第一个场景走完.

  • 第二个场景,我们把我们的liearlayout中的dispatchTouchEvent返回true,

    我们猜想是这样的,如果返回true,事件就在当前的方法中终止了也就是在liearlayout中终止,所以其他的方法根本不会接收到这个事件,所以看下我们执行的log输出,

这里以为linearlayout中dispatchonTouchEvent返回了true,事件在这里终止了,所以我们的返回箭头就接收不到事件,于是我们的返回按钮就失效了.

  • 第二个场景,我们让linearlayout的dispatchonTouchEvent返回false,那么这个触摸事件将是一个怎么样的过程呢?

    dispatchonTouchEvent.返回false,事件要被来自哪里,就要被返回哪里,假如我们的linearlayout还有父view ,那么这个事件将返回给父view的onTouchEvent事件处理,如果来自activity,那么将被activity的onTouchEvent处理,看下我们的log输出;

![这里写图片描述](http://img.blog.csdn.net/20160331173347685)

当我们点击我们的返回箭头的时候,因为事件从liearlayout中返回给了activity消费,所以子控件没法接收到事件,所以点击返回的箭头也无法生效;

  • 第三个场景,linearlayout中的onInterceptTouchEvent返回true,其他返回super,猜想,拦截事件返回true,那么事件不会传递给子view,

    返回按钮不会生效.因为我们其他的方法都是返回到 super,所以事件在onTouchEvent中返回了给其父view 或者activity,由于activity中的onTouchEvent也返回到 super,所以事件消失,..具体看log输出的过程和解释

因为事件也在activity中,并没有传递给子view 所以返回按钮失效

  • 下一个场景,让我们的liearlayout中的onInterceptTouchEvent返回false,不拦截,那么事件将会传递给子view,子view在去调用自己的dispatch方法去纷发,这样事件就能被返回箭头接受,可以正常关闭activity

    我们看下log输出,

由于onInterceptTouchevent返回了false,所以事件执行完他里面的方法后就把事件传递给了子view,于是事件就从发源地activity 和linearlayout中的 dispatch 和 intercept 起作用,并没有onTouchEvent的事情了,具体细节看log输出描述,然后由于事件传递给了子view 所以 返回箭头生效,这个方法返回false和返回super产生的效果是一模一样的,这里就不在截图了有兴趣的可以输出一下

  1. 到此为止我们activity中只有一个viewgroup的场景基本分析完毕了,然后我们想liearlayout中添加一个textview如下图

因为我们这里加入的是最小单位的view就是view不能再添加额外的内容,我们手指触摸屏幕事件传递过程,有activity 到 liearlayout 在到view 在返回 linearlayout ,返回activity 直到消失,具体过程如下;

再来一个场景,这次我们让childview中的dispatch 事件返回false,

笔者本来也是对这个传递有点模糊的,今天博客写到这里我都能猜到打印结果了,由于textviewdispatch返回了false ,所以事件执行完dispatch down后直接把事假返回给父view linearlayout的onTouchEvent,由于onTouchEvent设置了touchlistener 所以后执行,然后就是父view也返回了super,所以事件传递给activity的onTouchEvent 由于activity的onTouchEvent也返回了super.所以事件消失,最后在activity中执行 move 和 up

然后我们看下打印结果;

写到这里,理解的事件传递在脑海里的模糊场景已经有点透明了,还需要更多的实践,文中可能有理解不到位的也请大神批正,到此我理解的事件传递在viewgroup 和view中全部结束,也感谢群里nil的指点谢谢!

如果你看完还是对这个过程不是很理解,请自己模拟场景打印log,因为我感觉没有在比笔者更笨出身更贫寒的了,当你模拟看log有点想吐甚至能猜到不同的返回值会是什么样的传递场景,那么你对事件传递的过程相比之前你的理解肯定有恍然大悟的!谢谢….

时间: 2024-10-07 19:18:21

Android_事件纷发的相关文章

= 电话拨号器/点击事件写法 =发短信

= 电话拨号器/点击事件写法 = 开发安卓应用步骤: - 1. 写UI, 即布局文件. - 2. 写代码, Activity, ContentProvider, Service, 等等. - 3. 在清单文件中配置 Activity 等四大组件. - 4. 在清单文件中添加权限. 下面开发一个电话拨号器应用. 首先是写布局文件: {{{class="brush:xml" <?xml version="1.0" encoding="utf-8"

Android基础之五:四大组件(Broadcast Receiver)

Broadcast Receiver作为Android四大组件之一,在整个系统中广泛运用,系统中存在各种各样的广播机制,例如下载,网络等都有具体的广播接收器 广播在很大程度上简化了开发,可以通过广播监听系统状态变化,监听另一App中事件传递,可以接收当前App中不同组件,不同UI.不同线程之间的消息传递 广播的创建与使用 创建一个继承自BroadcastReceiver类的子类,重写onReceiver方法 public class MReceiver extends BroadcastRece

QT开发(六十三)——QT事件机制分析

QT开发(六十三)--QT事件机制分析 一.事件机制 事件是由系统或者QT平台本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事件则是由系统自动发出,如计时器事件. 事件的出现,使得程序代码不会按照原始的线性顺序执行.线性顺序的程序设计风格不适合处理复杂的用户交互,如用户交互过程中,用户点击"打开文件"将开始执行打开文件的操作,用户点击"保存文件"将开始执

关于编写性能高效的javascript事件的技术

如何能做出高效的web前端程序是我每次做前端开发都会不自觉去考虑的问题.几年前雅虎里牛逼的前端工程师们出了一本关于提升web前端性能的书籍,轰动了整个web开发技术界,让神秘的web前端优化问题成为了大街的白菜,web前端优化变成了菜鸟和大牛都能回答的简单问题,当整个业界都知道了惊天秘密的答案,那么现有的优化技术已经不能对你开发的网站产生的质的飞越,为了让我们开发的网站性能比别人的网站更加优秀,我们需要更加深入的独立思考,储备更加优秀的技能. Javascript里的事件系统是我想到的第一个突破

WPF学习之事件(一)

就像属性系统在WPF中得到升级.进化为依赖属性一样,事件系统在WPF中也被升级,从而进化成为——路由事件(Routed Event),并在其基础上衍生出命令传递机制.就让我们一起来领略这些新消息机制的风采吧! 1.近观WPF的树形结构. 路由(Route)一词的大意为:起点和终点之间有若干个中转站,从起点出发后经过每个中转站时都要进行选择,最终以正确(比如最短或者最快)的路径到达终点.我们知道,WPF的UI是由布局组件和控件构成的属树形结构.因此,当这棵树上的某个节点激发出某个事件的时候,程序员

.NET基础拾遗(4)委托、事件、反射与特性

Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 一.委托基础 1.1 简述委托的基本原理 委托这个概念对C++程序员来说并不陌生,因为它和C++中的函数指针非常类似,很多码农也喜欢称委托为安全的函数指针.无论这一说法是否正确,委托的的确确实现了和函数指针类似的功能,那就是提供了程序回调指定方法的机制. 在委托内部,包含了一个指向某个方法的指针(这一点上委托实现机制和C++的函数指针一致),为何称其

Android事件机制

一句话描述: 用户和程序之间的互动机制 什么是事件? 用户和程序交互时触发的程序操作. 只要是事件,必须具备三方面: 1 事件的发生者 2 事件接受者 3 事件触发和传递 事件处理的方法 观察者模式:事件源就必须拥有一个观察者的引用  传递:靠调用观察者的方法     然后把数据传递过去 预定义事件(发生者):单机,双击,长安等,并以类的成员变量分别表示这些事件 这些控件的成员变量按事件的类型定义为不同类型的借口.因此,这些成员变量存放的对应借口的实现类的对象地址 程序员事先编写好实现了某个接口

转:委托和事件详解

Delegate delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类.与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与它的签名相匹配的方法的引用".它所实现的功能与C/C++中的函数指针十分相似.它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m.但与函数指针相比,delegate有许多函数委托和事件在 .Net Framework中的应用非常广泛指针不具备的优点.首先,函数指针只能指

关于c#的事件如何使用

委托事件的详细使用 一.无参数,无返回的委托事件 委托事件类.事件的发生源 1 public class Test 2 { 3 // …. 4 public delegate void TestHandler();//无参数,无返回委托 5 public event TestHandler TestEvent;//事件 6 public void OnTestHandler()//调用 7 { 8 if(TestEvent != null) //不等于null 说明该事件已经注册有函数 9 {