大话android事件传递机制

作者: 码无止境 | 来源:发表于2016-09-09 12:08 被阅读428次

    背景

    看了很多关于android事件传递的技术博客,写得特别官方,不接地气,让人看了以后不是特别深刻。特别在遇到一些滑动冲突问题上面,不知道如何去解决,大概知道有dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个方法可以解决问题,然后尝试着一个一个return ture or false解决问题,虽然运气好解决了问题,但为何是那样?却一知半解。

    目的

    通俗易懂地帮助大家去理解android事件传递机制,能举一反三地解决事件传递相关的疑难杂点。

    主题

    今日笔者带领大家从代码的角度去分析android事件传递机制,解开大家心里的疑惑。大家从各种技术渠道都大致了解了事件传递机制有两大主角,分别是ViewGroup、View。然后会有童鞋会问,那activity呢?其实activity可归类ViewGroup。在事件传递机制中,了解过事件传递的童鞋应该知道ViewGroup有三个方法分别对应:分发事件(dispatchTouchEvent)、拦截事件(onInterceptTouchEvent)、消费事件(onTouchEvent);View只有两个方法,跟ViewGroup区别,就少了一个拦截事件(onInterceptTouchEvent)。

    分发事件(dispatchTouchEvent)

    • 将事件分发下去
    • 类似领导分发工作

    拦截事件(onInterceptTouchEvent)

    • 事件分发后是否需要拦截?
    • 类似领导分发工作之后的一次确认,是否工作真的需要分发下去?

    消费事件(onTouchEvent)

    • 事件是否消费?
    • 类似分发的工作是否完成?如果完成了,表示这个工作已经完结,不需要再继续分配了。

    接下来我们开始从代码的角度分析android事件传递机制,首先我们创建一个自定义ViewGroup和一个自定义View,分别为CustomLayout、CustomView。
    CustomLayout可用对应代码如下:

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            System.out.println("dddddddddddddddddd CustomLayout dispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            System.out.println("dddddddddddddddddd CustomLayout onInterceptTouchEvent");
            return super.onInterceptTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // CustomButton onTouchEvent
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    System.out.println("ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_DOWN");
                    return true;
                case MotionEvent.ACTION_UP:
                    System.out.println("ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_UP");
                    break;
            }
            System.out.println("ddddddddddddddddddddd CustomLayout onTouchEvent(event) = " + super.onTouchEvent(event));
            return super.onTouchEvent(event);
        }
    
    

    CustomView可用对应代码如下:

      @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            System.out.println("dddddddddddddddddd CustomView dispatchTouchEvent");
            return super.dispatchTouchEvent(event);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    System.out.println("ddddddddddddddddddddd CustomView onTouchEvent ACTION_DOWN");
                    break;
                case MotionEvent.ACTION_UP:
                    System.out.println("ddddddddddddddddddddd CustomView onTouchEvent ACTION_UP");
                    break;
            }
            System.out.println("ddddddddddddddddddddd CustomView onTouchEvent(event) = " + super.onTouchEvent(event));
            return super.onTouchEvent(event);
        }
    
    

    然后app run起来,结果如下:

    09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
    09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout onInterceptTouchEvent
    09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomView dispatchTouchEvent
    09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent ACTION_DOWN
    09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent(event) = false
    09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_DOWN
    09-09 10:45:42.458 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
    09-09 10:45:42.458 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_UP
    09-09 10:45:42.458 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomLayout onTouchEvent(event) = false
    
    

    我们发现最先执行的是ViewGroup里面的dispatchTouchEvent(事件分发)方法,然后onInterceptTouchEvent(事件拦截),ViewGroup未拦截,就将事件传递给了View,执行了View的dispatchTouchEvent(事件分发)方法,接着是View的onTouchEvent事件,而View的onTouchEvent事件中最先执行的是ACTION_DOWN方法,然后发现View的onTouchEvent事件并没有消费事件(类似没有完成任务),就将该事件又传回给了ViewGroup,此时执行 ViewGroup的onTouchEvent事件,然后ViewGroup重新分发事件,这时没有把事件给View,而是直接执行了ViewGroup的onTouchEvent事件,然而自己也未消费该事件,该事件会继续往上传,依次类推。

    此时如果我们将View中ACTION_DOWN事件给返回true,结果会如何呢?请看下面:

    09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
    09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout onInterceptTouchEvent
    09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomView dispatchTouchEvent
    09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent ACTION_DOWN
    09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
    09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout onInterceptTouchEvent
    09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomView dispatchTouchEvent
    09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent ACTION_UP
    09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent(event) = false
    
    

    从上面结果可知,当在View中onTouch ACTION_DOWN动作消费了onTouch事件,当执行ACTION_UP动作,事件依然会将事件分发给View处理。

    根据上面结果做个总结,ViewGroup类似领导,View类似下属,事件类似工作任务,领导给下属分配工作任务,如果下属能按时完成工作任务,那么领导下次安排工作任务时,就会将工作任务继续分发给该下属,否者就领导看自己能否处理该工作任务,不能处理就直接把工作任务反馈给他的直接上司,依次类推。

    扩展

    这里进行一下扩展,onTouch跟onClick有啥关系?也许有童鞋会思考这个问题。当onTouch action为ACTION_DOWN时,如果返回ture(直接消费了该事件,类似下属处理了动作为ACTION_DOWN的工作,则不会再触发onClick事件和onLongClick事件)。

    看了这篇文章,童鞋们是不是对android事件传递有了彻底的理解呢?

    如有疑问,请留言。

    关于作者

    相关文章

      网友评论

      本文标题:大话android事件传递机制

      本文链接:https://www.haomeiwen.com/subject/axyeettx.html