一张图看透Android事件传递机制

一、引言

        总觉得知识必须要总结,不然就算再熟悉的东西,一段时间不接触就容易遗忘;上次给一个朋友解释回调的时候就有深刻的体会,所以现在养成总结的习惯,而我觉得最直观的方法就是图解,所以就有了下面的图,通过这张图看透Android事件传递机制;
        PS:有时候自己的理解可能也存在问题,所以通过这种形式能够得到大家的审查和修改意见,在这里先谢谢大家了!

二、就是这张图(自己看了一下,这张图看不清楚,复制或保存本地,使用图片查看器放大查看;或者点击链接查看原图)


三、图片局部细节详解

1.Touch事件的传入  :


            
            开始由UserActivity(用户自定义的Activity)接收到事件,这个类继承自Activity,没有 onInterceptTouchEvent方法(为什么没有?谁能给我一个合理的解释吗?)
事件传递到 disPatchTouchEvent,这里默认的是调用父类的disPatchTouchEvent,查看父类的源码可以看到,
    /**
     * Called to process touch screen events.  You can override this to
     * intercept all touch screen events before they are dispatched to the
     * window.  Be sure to call this implementation for touch screen events
     * that should be handled normally.
     * 
     * @param ev The touch screen event.
     * 
     * @return boolean Return true if this event was consumed.
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

            这里的第一个判断条件中方法的执行为为空实现:

            第二个判断中的判断条件是有窗体事件分配决定的,窗体默认的事件分发机制,再往里面看,如下代码
    /**
     * Used by custom windows, such as Dialog, to pass the touch screen event
     * further down the view hierarchy. Application developers should
     * not need to implement or call this.
     *
     */
    public abstract boolean superDispatchTouchEvent(MotionEvent event);
    
               可以理解为Android系统自己定义的事件分发机制,上面说明了应用开发者不需要去实现或者调用这个方法。我理解的是系统已经为你准备好了普通窗口事件该如何分发,不需要你再手动去修改这块代码了!如果你不按照我的方法来做,那么好吧,后面的事你都自己干吧,就是这么任性。所以在UserActivity中手动修改dispatchTouchEvent方法的返回值,就会使本次事件被消费掉,不再向里层传递。
顺带看看onTouchEvent方法吧:
    /**
     * Called when a touch screen event was not handled by any of the views
     * under it.  This is most useful to process touch events that happen
     * outside of your window bounds, where there is no view to receive it.
     * 
     * @param event The touch screen event being processed.
     * 
     * @return Return true if you have consumed the event, false if you haven't.
     * The default implementation always returns false.
     */
    public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }
        
        return false;
    }

          从上面的说明可以看出,当触屏事件没有被内层所有的view处理的时候才会被调用;当处理你窗体外没有任何view处理的Touch事件的时候最有用。
          从返回值说明可以看出,默认返回值通常为false,所以一般如果事件不被子view消费,事件一般都会被舍弃掉


2.从Activity中传入外层的ViewGroup中


                经过了UserActivty后传入到ViewParent中来,第一个走的肯定还是dispatchTouchEvent,依然,如果手动修改dispathTouchEvent的返回值,本次事件就到此为止。如果使用父类(ViewGroup)的事件分发机制,那么事件就会首先传递到onInterceptToucEvent中来;(这部分里面代码太多,我想你也没兴趣看;万一你是个Geek,那你也可以自己去扒一扒源码,自己阅读一下,这里就不再详细介绍了,本文就是为了言简意赅的说明Touch事件的传递机制,所以见谅)
在onInterceptTouchEvent中,就会询问你“你想不想拦截本次事件啊?”
|--“想”(return true),那么事件就会进入自己的onTouchEvent中执行
        那么事件就会到了onTouchEvent中,这时系统就会问你:“你想不想处理这次点击事件啊?”
            |--“想”(return true)那么本次事件被消费掉了
            |--“不想”(return false)那么他就会认为你里层的子控件都不想接收本次事件,那他直接把本次事件往回传递(传回UserActivty中去处理)。需要注意的是,如果 本次事 件是DOWN事件,那么本次的MOVE、UP也将不会传递到ViewParent中来了,注意是本次哦,仅仅只是指你一次按下到抬起这一套动作,还有第二 次,第三次,还是要来的。
            |--"你自己说了算,按照你的想法去做吧!"(return super.onTouchEvent(ev);)那就要交给ViewParent的父类去决定了,不过一般ViewGruop中都不会去处理事 件,即一 般返回false
|--“不想”(return false),既然你不想拦截,那我就去问问你里面的人想不想处理吧,事件就会向里层传递,即下面的ViewChild
|--“你自己说了算,按照你的想法去做吧!”(return super.onTouchEvent(ev);),系统当然是想有人来消费这个事件了,既然你让我自己决定,那我也想向你里面的子控件 问问啊!

3.事件传递到了ViewChild中


这里当然是最里层控件了.
        dipatchTouchEvent:还是和上面的一样,还是决定是否分发事件,系统的逻辑会自动运行到自己onTouchEvent方法中,如果你主动干预,决定是否分发(手动更改返回值),事件到这里就会终结
       onInterceptTouchEvent:最里层控件没有这个方法,既然是最里层的控件,自然就不需要询问你是否需要拦截这个事件了,因为你拦不拦截,事件到这里就算是走到了路的尽 头(之所以称为路的尽头,是因为还可以走走回头路的,哈哈!)所以这里没有啊onInterceptTouchEvent方法
        onTouchevent:逻辑和之前的一样,问你是否消费本次事件,
               |-- return true消费掉本次事件,事件结束;
               |-- return false不消费,本次事件回传到外一层控件,同样,如果是一次DOWN事件,本次的MOVE和UP将不会再传递到这里;
               |-- return super.onTouchEvent(event) 是否消费本次事件就要看自己控件类型了,我的例子中是TextView类型,就是不消费的;

4.事件回传

         事件回传,差不多是同一种情况,就是当前控件中的onTouchEvent返回值为false(默认的super.onTouchEvent方法一般也是返回false),可以理解为:
                   |-- return false:事件都交到你手里了,而且你明确说了你不要,那我只能往回传了;
                   |-- return super.onTouchEvent(event):如果你不告诉我你要不要处理,我只能默认你不处理,也就往上一层传递了
        当到达了最顶层,我的Demo程序中是MainActivity,默认不处理onTouchEvent,所以如果回传到顶层,事件会调用Activity中的onTouchEvent

本次分析到这里就算结束了,感觉有些地方的理解还存在问题,欢迎各位大神指点,先谢过了!

本次使用的图片资源和源代码,如需要,请自行下载:
链接: http://pan.baidu.com/s/1kTH59sj 密码:1m5n





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值