移动架构13_责任链模式分析Android事件分发机制

原创 2017年10月06日 21:01:08
一、责任链模式简述
定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,
将这些对象形成一条链,并沿着这条链传递该请求,直到有对象处理它为止
 ss
 重点:上一个处理对象必须含有下一个处理对象的引用,形成一个单向链表
Android事件传递:OnTouchEvent---请求 ---》View  ViewGroup  Activity 都有机会处理他
ss

 二、以责任链模式对比事件分发
模式 事件分发
上一个对象持有下一个对象 Activity持有Window对象,Window包含View对象
请求传递 DispatchEvent:Activity传给Window->ViewGroup -(遍历)-View
处理请求 onTouchEvent
每个对象所处理请求不同的抽象 TouchEvent



三、Android事件分发机制
1、带着问题分析源码
1 )在ViewGroup中重写onInterceptTouchEvent方法返回true为什么会拦截事件,
并且该ViewGroup会消费了Event(调用onOnTouchEvent)。
2  )为什么事件不再向子控件继续传递?
3)当父控件没有拦截事件时,事件是如何传递到子控件的
4)点击事件中的x,y坐标值都是以父布局的相对坐标,这里又是如何一层一层转换的?
在ViewGroup的dispatchTransformedTouchEvent方法中:
if(child ==null) {
handled =super.dispatchTouchEvent(event);
}else{
final float offsetX = mScrollX - child.mLeft;
final floatoffsetY = mScrollY - child.mTop;
//做了偏移,View相对于ViewGroup的距离
event.offsetLocation(offsetX, offsetY);

handled = child.dispatchTouchEvent(event);

event.offsetLocation(-offsetX, -offsetY);
}
ss
5)为什么给自定义View设置OnTouchListener后不再调用 重写的onTouch方法
 
 2、事件分发机制分析
用户点击屏幕作为发送者 ,每个ViewGroup  和View作为处理者
1),用户点击屏幕作为发送者,Activity、Window、VieGroup作为接受者。他们之间任何对象都能处理事件请求
2)activity、Window、ViewGroup之间的依赖关系形成了调用链
3)事件可以依赖这条调用链传递请求

3、源码分析
1)Activity最先接受到事件,调用dispatchTouchEvent方法
public booleandispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if(getWindow().superDispatchTouchEvent(ev)) {
return true;
}
returnonTouchEvent(ev);
}
如果Window的superDispatchTouchEvent()返回true,整个方法返回true;否则,会调用Activity的OnTouchEvent方法

2)Activity的分发会调用Window的superDispatchTouchEvent方法
Window仅有一个实现类,PhoneWindow;其实现了superDispatchTouchEvent方法:
public booleansuperDispatchTouchEvent(MotionEvent event) {
returnmDecor.superDispatchTouchEvent(event);
}
DecorView中:
public booleansuperDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
mDecor->DecorView ->FrameLayout -> ViewGroup
调用了ViewGroup的dispatchTouchEvent方法

3)ViewGroup的dispatchTouchEvent中
(1)如果ViewGroup的onInterceptTouchEvent返回true,则事件不会向下传递,会传递到ViewGroup的onTouchEvent中去
dispatchTouchEvent:
...
intercepted = onInterceptTouchEvent(ev);//true
....
if(!canceled && !intercepted) {//intercepted= true,不执行这段逻辑
....
finalView[] children =mChildren;
for(inti = childrenCount -1; i >=0; i--) {
//循环查找子View进行传递的逻辑
...

代码执行:
handled = dispatchTransformedTouchEvent(ev, canceled,null,
TouchTarget.ALL_POINTER_IDS);
(传入的第三个参数为null)

dispatchTransformedTouchEvent中:
if(child ==null) {
handled =super.dispatchTouchEvent(event);
}
调用父类的dispatchTouchEvent,即View的dispatchTouchEvent:
if(li !=null&& li.mOnTouchListener!=null
&& (mViewFlags&ENABLED_MASK) ==ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result =true;
}

if(!result && onTouchEvent(event)) {
result =true;
}

如果设置了mOnTouchListener,则不调用onTouchEvent方法;否则调用onTouchEvent方法

(2)如果ViewGroup的onInterceptTouchEvent返回false
就会走到上面没有执行的if中代码快,遍历ViewGroup的所有child
for(intj = 0; j < childrenCount; j++) {
判断事件是否在child的边界范围内,获取一个View类型的child
同样执行了dispatchTransformedTouchEvent方法,但这次传入的是遍历的child而不是null,进入dispatchTransformedTouchEvent方法,执行了代码:
handled = child.dispatchTouchEvent(event);
事件传递到了child中去,也就是调用了View的dispatchTouchEvent方法


4) View的dispatchTouchEvent方法
View的dispatchTouchEvent中:
if(!result && onTouchEvent(event)) {
result =true;
}
也可能调用View自己的onTouchEvent方法

如果View的onTouchEvent返回true,那么View的dispatchTouchEvent返回true;
返回到ViewGroup中调用View的dispatchTouchEvent地方,即dispatchTransformedTouchEvent方法,
dispatchTransformedTouchEvent(...){
....
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
returnhandled;
}
返回true;

而dispatchTransformedTouchEvent是在ViewGroup的dispatchTouchEvent中遍历子控件地方调用的
...
if(dispatchTransformedTouchEvent(ev,false, child, idBitsToAssign)) {
//进入到这段逻辑中
mLastTouchDownTime= ev.getDownTime();
if(preorderedList !=null) {
// childIndex points into presorted list, find original index
for(intj = 0; j < childrenCount; j++) {
if(children[childIndex] ==mChildren[j]) {
mLastTouchDownIndex= j;
break;
}
}
} else{
mLastTouchDownIndex= childIndex;
}
mLastTouchDownX= ev.getX();
mLastTouchDownY= ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget =true;
break;
}

如果找到了接受事件的控件,那么下一次就会直接去找它的onTouchEvent;
原因就是addTouchTarget,mFirstTouchTarget 被赋值
privateTouchTarget addTouchTarget(@NonNull View child,intpointerIdBits) {
finalTouchTarget target = TouchTarget.obtain(child, pointerIdBits);
target.next=mFirstTouchTarget;//这也是一个责任链
mFirstTouchTarget= target;
returntarget;
}
而break使得其他子控件不会接触这个事件


5) 事件分发示意图
ss
 
注意:
通常一个ViewGroup事件不拦截,则传递给子ViewGroup,还不处理,继续向下传递,如果最终不传递;那么看父ViewGroup是否处理,不传递“向上”传递,直到传递给最上一层。但是值得注意的是,并没child.super处理事件的方法,也就是说并不是底层传递上来的。这是一个递归,有一点像二叉树的遍历,以一个ViewGroup为例,实际代码是看其child是否消费事件,如果没有被消费,然后自己会去super.dispatchonTouchEvent(当前的父类,不是向上),来到自身的的onTouchEvent。总结:不是向上,而是递归
ss
 
 
 
 
 






android控件之间事件传递

Android Viewpage禁止滑动屏幕,viewpage中轮播图可以手动滑动设置等。
  • xiaoyi848699
  • xiaoyi848699
  • 2014年11月11日 17:59
  • 870

Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

其实我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客开始,就零零散散在好多地方使用到了Android事件分发的知识。也有好多朋友问过我各种问题,比如:onTouch和onTouc...
  • sinyu890807
  • sinyu890807
  • 2013年06月20日 08:30
  • 322484

Android 事件传递

网上有不少关于View 的事件传递的相关文章,其实写的都还不错, 这里我自己写来整理一下,关于View 事件传递的相关文章, 来加深自己对于事件的处理 这几天写博客,发现, 不仅能够加深自己对已知...
  • chen930724
  • chen930724
  • 2015年11月01日 16:45
  • 376

Android开发-事件分发机制实验分析ViewGroup、View事件分发,结合职责链模式

介绍上一篇博客职责链/责任链模式(Chain of Responsibility)分析理解和在Android的应用 介绍了职责链模式,作为理解View事件分发机制的基础。 套用职责链模式的结构分析...
  • Card361401376
  • Card361401376
  • 2016年06月01日 18:01
  • 4635

移动架构12_责任链模式

一、定义 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象形成一条链,并沿着这条链传递该请求,直到有对象处理它为止。 二、使用场景 多个对象能够处理同一请求...
  • baopengjian
  • baopengjian
  • 2017年10月05日 21:51
  • 311

Android ViewGroup 触摸事件传递机制

引言上一篇博客我们学习了Android View 触摸事件传递机制,不了解的同学可以查看Android View 触摸事件传递机制。今天继续学习Android触摸事件传递机制,这篇博客将和大家一起探讨...
  • feidu804677682
  • feidu804677682
  • 2015年08月01日 22:44
  • 3395

Android事件传递机制详解(嵌套自定义View示例)

一、概述   自定义View如果嵌套了自定义View,可能简单写一个onTouchEvent处理事件已经不能解决你的需要。简单举个例子:   你自定义了一个容器View,简称为父View,在这里监听点...
  • a369414641
  • a369414641
  • 2016年10月20日 17:40
  • 878

Android事件分发机制 详解攻略,您值得拥有

前言 Android事件分发机制是Android开发者必须了解的基础 网上有大量关于Android事件分发机制的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化等等 今天,我...
  • carson_ho
  • carson_ho
  • 2017年01月06日 11:43
  • 38487

一步步理解Android事件分发机制

回想一下,通常在Android开发中,我们最常接触到的是什么东西?显然除了Activity以外,就是各种形形色色的控件(即View)了。 与此同时,一个App诞生的起因,终究是根据不同需求完成与用户...
  • ghost_Programmer
  • ghost_Programmer
  • 2016年07月21日 18:57
  • 2697

Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

记得在前面的文章中,我带大家一起从源码的角度分析了Android中View的事件分发机制,相信阅读过的朋友对View的事件分发已经有比较深刻的理解了。 还未阅读过的朋友,请先参考 Android事件分...
  • sinyu890807
  • sinyu890807
  • 2013年07月05日 08:26
  • 104365
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:移动架构13_责任链模式分析Android事件分发机制
举报原因:
原因补充:

(最多只允许输入30个字)