面试题记录第七节——(事件分发)

来源:互联网 发布:python 赋值 变量名 编辑:程序博客网 时间:2024/06/05 14:22

一、问:为什么会有事件分发机制

答:我们知道Android中的view,是以树形结构存在的。他的view控件有可能会重叠在一起,当我们点击的地方存在多个view的时候,就会导致我们的点击事件,多个view都得到响应,这个时候系统会把这个点击事件判断给谁呢?为了解决这个问题,就有了事件分发机制。

  • 如下图,当我们点击view1的时候,它下面的viewGroupA和黑色的rootview,都会得到相应。为了确定到底是view1还是ViewGroupA,又或者是RootView来处理一个点击事件。这里就引入了事件分发机制。

这里写图片描述

  • 我们再看一下图的布局结构

这里写图片描述

  • 问:这里我们看到了最上方的两个是PhoneWindow和DecorView,这两个我们在布局当中几乎没有见到过,他们到底是什么呢?

  • 答:

    我们在图01的时候,就会发现灰色默认背景颜色和橙色标题栏都是在布局之外,他们两个就是在DecorView中存在。

    PhoneWindow他是一个抽象类window的实现类,抽象类window它是所有视图最顶层的容器,所有的View或者ViewGroup的行为都是归抽象类Window来管理,这里包括了背景的显示,标题栏、事件的处理都是在抽象类Window的管理之内,抽象类Window就是最顶层的view管理工具。虽然看起来它管理的很多,但是因为它是抽象类,他无法真正的处理,所以它只能交给它的唯一实现类PhoneWindow来处理,PhoneWindow就是我们的view事件管理容器。不过一般情况下PhoneWindow都是通过他的一个内部类DecorView来进行消息的传递,PhoneWindow他通过指示告诉DecorView传递给下面的View,而下面的view信息也通过DecorView返回给PhoneWindow。


二、我们一直再说事件传递、事件分发,但是他们到底是一个什么过程呢??

答:他其实就是通过三个重要的方法来实现的

dispatchTouchEvent:处于列首的位置,也是最重要的,它决定了触摸事件是有自己的onTouchEvent来处理还是交给子View,让子View递归调用自身的onTouchEvent来处理。

oninterceptTouchEvent:它是用来拦截事件的,当父控件下发事件给子View处理的时候,如果子控件需要对事件进行处理,他就会在onInterceptTouchEvent这个方法中进行拦截,然后他就会到子控件的onTouchEvent方法中做触摸事件监听以及一些逻辑的判断。

onTouchEvent:onTouchEvent它是view里面的一个方法,他处理传递到view的什么事件,比如按下屏幕、拖动等操作。


三、事件分发流程?

答:Activity — PhoneWindow — DocorView — ViewGroup—>>—View

当屏幕被点击的时候,由于view是树形结构,

第一步:事件首先会传递给Activity。

第二步:传递到View的实现管理类PhoneWindow。

第三部:而PhoneWindow是通过他的内部类DecorView 来传递的。

第四步:DocorView又会传递给最大的父容器ViewGroup。

第五步:DocorView 又会依次传递给它的子View。


四、如果事件传递到了最后一个View,而这个view也没有处理这个事件,怎么办?这个事件会不会被浪费掉呢?

答:不会浪费掉,因为android中有这样一个机制,如果最后一个view没有处理传递过来的事件,那这个事件就会依次反转,最后返回最高位的activity。如果最后activity也没有处理,这个事件才会被抛弃。所以事件不会在传递到最后一个View没有得到处理就被抛弃掉(其实这个模式也就是Android中的责任链模式)。

  • 我们来看一个例子:如图01(是不是一看就懵逼,不要着急,深呼吸,看下面一步步来分析)。
    这里写图片描述

  • 效果:我们点击了view1之后,其他的父控件不进行拦截,而只有view1进行拦截。

过程:

1、首先事件会传递给activity中,activity会在他的dispatchTouchEvent中来进行处理,

2、他会传递给PhoneWindow,而PhoneWindow会调用它本身的内部类DecorView中的dispatchTouchEvent。此时会判断是否进行拦截,如果不拦截的话,继续往下传。

3、如果不拦截的话,就会穿第给RootView中的dispatchTouchEvent方法中分发,而在Rootview中也会通过onInterceptTouchEvent方法中进行判断是否拦截,如果不拦截就会继续下传。

4、此时ViewGroupA就会接收到RootView传递过来的事件,也会通过dispatchTouchEvent方法来进行事件的分发,通过onInterceptTouchEvent方法中进行判断是否拦截,如果不拦截就会继续下传。

5、此时View1就会得到传递下来的事件。view在它自身的dispatchTouchEvent方法中进行相应的处理,这时候它是我们案例中最底层的view。他就没有拦截时间了。如果View1的onTouchEvent返回了true。就说明view1消费掉了此事件。这个时候我们会依次返回true。依次告诉上层的dispatchTouchEvent方法,事件已经被处理了。就不要再做此事件的相应了,最后到最顶层Activity中。


推荐一篇不错的博客:
http://www.jianshu.com/p/2be492c1df96

想看源码分析:http://blog.csdn.net/guolin_blog/article/details/9097463/

原创粉丝点击