移动架构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进阶系列之源码分析事件分发责任链模式

翱翔于源码的海洋,痛并快乐着.... 什么是责任链模式? 责任链模式(Chain of Responsibility)的目标是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系...

设计模式--[5]责任链模式和Android事件分发

我的理解:一种行为模式,为请求创建一个接收者的对象链.这样就避免,一个请求链接多个接收者的情况.进行外部解耦.类似于单向链表结构.应用场景:JS 中的事件冒泡,jsp servlet 的 Filter...
  • ccj659
  • ccj659
  • 2016年12月30日 10:47
  • 370

Android责任链模式简单Demo

  • 2016年02月21日 00:41
  • 1.22MB
  • 下载

【设计模式 - 13】之责任链模式(Chain Of Responsibility)

1      模式简介 责任链模式的简介: 1.        责任链模式为请求创建了一个接收者对象的链,每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给...

设计模式(13)-责任链模式

职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象...

android设计模式-责任链模式与View Touch Event分发

背景与问题差旅费申请场景 组员申请1w->组长(0~3k)->主管(0~5k)->经理(0~8k)->老板(0~2w) 组员只与组长具备关联,并不关心具体处理者是谁。 在开发中,许多对象都可能接...

JAVA设计模式(13):行为型-责任链模式(Responsibility)

“一对二”,“过”,“过”……这声音熟悉吗?你会想到什么?对!纸牌。在类似“斗地主”这样的纸牌游戏中,某人出牌给他的下家,下家看看手中的牌,如果要不起上家的牌则将出牌请求再转发给他的下家,其下家再进行...

设计模式之13 - 责任链模式Chain Of Responsibility

条件判断 在编程中是应用最广的,他决定了程序的下一步应该怎么执行。我们来看下面一段代码: // 条件判断 string strType = ""; if(age...

JAVA设计模式(13):行为型-责任链模式(Responsibility)

定义 将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求, 如果能则处理,如果不能则传递给链上的一个对象。 场景: 打牌时,轮流出牌接力赛跑大...

设计模式(13)------责任链模式

责任链模式作用: 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。 将这些对象连接成一条链,并根据这条链传递请求参数,直到有某个对象处理请求为止。 使用这一模式,是想给多个对象...
  • yhl_jxy
  • yhl_jxy
  • 2016年10月01日 13:06
  • 213
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:移动架构13_责任链模式分析Android事件分发机制
举报原因:
原因补充:

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