从系统源码角度分析Android事件分发

来源:互联网 发布:广联达预算软件价格 编辑:程序博客网 时间:2024/06/06 04:16
从系统源码角度分析Android事件分发
 之前看大牛的博客关于Android事件分发的机制,似懂非懂,自己做了测试,很多地方有问题,并不能用大牛们的理论解释通,也就没有继续下去。这次自己要用到了事件分发就各种查资料研究了,被逼无奈了。终于在几天的研究下有了成果。
   一起学Android的好友们,你们有福利了。还是分享会给人带来快乐啊。
    好了,废话不多说了,说Android的事件分发机制吧。Android的事件是有类MotionEvent这个类来管理的,打开这个类,看源码可以知道,事件是从Parcel这个类传过来的。这个Parcel这个类调用的都是本地方法,也就是JNI了,事件从Android系统底层传上来,最先到达

MotionEvent这个类。然后是到达Activity了。中间省略了还有很多环节,但是都不重要了,咱们捡重要的理清思路。把这个给Activity之后就会出现三个处理方法,一个是分发,一个是中断,一个是处理,分别对应的是public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);和public boolean onTouchEvent(MotionEvent ev);这三个方法,其中中断事件方法只有VIewGroup有。 看Activity中的分发代码。

第一个if不用看,就是在判断是按下的事件去做了一个事情,跟我们没有关系,然后第二个if这个方法是关键,调用了window的superDispatchTouchEvent(ev)那这个Window是什么呢,是PhoneWindow,来看看这个方法里面是什么。

调用父类的分发方法,父类是谁呢,是FrameLayout,他继承的是ViewGroup,看了下FrameLayout的源代码,里面没有重写分发的方法,所以就直接看ViewGroup的分发方法就OK了。 看看主要几个处理。

首先DOWN事件是非常重要的。没有DOWN事件就不可能有MOVE和UP事件,上面的一些判断不用管,这是防止一些意外情况做的处理。可以忽略,主要看for循环里面,对子的View进行遍历,在小方框中可以看出,if判断里面就调用子View的分发方法,这样分发方法又从VIewGroup传到View中。如果子的View做了处理返回TRUE,也就是把事件消费了。那该ViewGroup就记录下消费了该事件的子View,然后返回TRUE,下面就不执行了。这是一种情况,先打个标记,就是有一个子View的dispatchTouchEvent返回了TRUE。子View可能是View,也可能是ViewGroup,如果是ViewGroup的话就一直这样重复下去,在这里也就不做研究了,同样的原理。如果是View的话,等下带大家去看下VIew的源码。先继续说这个ViewGroup。第二种情况是没有子View返回TRUE,则跳到下面继续执行。并且mMotionTarget为空了。来看下面的代码。



 首先判断目标View是否为空,如果为空则返回父类的分发方法。父类是什么呢,父类是View。就是说返回了自身的本来的分发方法。因为ViewGroup也是一个View。他返回什么呢?我们暂且先不管,但是我可以告诉你放回的是FALSE,等下把View的源码拿出来看看就知道了。先继续往下看。如果目标View不是空的,也就是有子的View消费了,就返回子View的分发,也就是说把事件传递到消费了Down事件的子View上去,可以看出DOWN事件的重要性了,如果子View没有消费DOWN事件的话,就接收不到后续的事件。如果你要屏蔽一个事件分发下去,就继承ViewGroup,重写分发方法,直接放回TRUE就可以了。就屏蔽了所有子View的事件。
        好了ViewGroup完成了。再去看看View的代码吧。

第一个if不用看,为了安全做的一个判断,第二个看到熟悉的东西了吧。有在写事件监听的时候注册监听事件么。如果写了,这里就会去检测,一般很少有人去注册这个监听的。所以if不成立,到了return后面的onTouchEvent方法了。所以整个流程到这里就清楚了。
    事件从ViewGroup一直往下分发,直到分发到View的时候再去调用TouchEvent方法。然后一层一层的往上返回,就像一个递归一样。
大家可能有点头晕,没关系,等下我画个图,帮大家理清思路。再去看下View的onTouchEvent的代码。 
     
这个方法下面就无关紧要了。也不去关注了。看方框里面的代码。这个是判断该VIew是否是可点击的,和可长按的。一般的View默认不可点击和不可长按的。所以写代码的时候设置clickable知道什么意思了吧。是在这里启作用的。如果不可点击,返回的是false.可点击继续往下。如果是不可点击就不能返回True,不能消费该事件,也就是不能监听。刚才看了ViewGroup的代码的时候有一个事情还未完成,就是
如果事件传到了 子View,子View返回了true消费了事件,返回到ViewGroup的dispatchTouch方法中的时候是直接返回TRUE的。也就是说直接结束了,一直往上传递TRUE,直到Activity中。但是如果没有子View消费事件,则调用父类View的分发方法。也就是会跳到自身的onTouchEvent中去执行。总结下。如果ViewGroup的分发事件被子View消费了,那自身的onTouchEvent就不会执行了。如果没有子View去消费,则会传到ViewGroup中的onTouchEvent中。该流程如图。
 
如果有一层返回TRUE,则终止往下走,在后面的方法就会被屏蔽。 
 这个是一个抽象的表述分发机制的图。再来一张基于源代码的。
 
所有的到此就讲完了。思路不知道清晰不清晰。如果大家还有疑问的话,最好去看源代码。所有的疑问都在源代码中找到解决的办法。
了解了事件分发的机制,学会巧妙的运用去重写这些方法,就可以自由控制界面中的事件传递。解决平常开发中出现的与事件有关的问题。比如在ListView中的Button不起作用,等等情况的原因就有个大致的了解。 

    希望这篇日记能帮到开发Android的好友。源代码还在继续看,等又有了一个方面的系统的认识后,再来发一些系统的介绍源代码的日志。希望大家等待更新。
1 0
原创粉丝点击