首页 欧洲联赛正文

appstore无法连接,Android 事情系统全面总结+实践剖析,亡羊补牢

在这之前看了许多相关文章,有一个全体知道今后,就要开端着手体会一下了。着手之前要清晰工作分发机制要研讨的是什么:工作序列在ViewGroup/View之间的传递规矩。

留意几点:

  • 研讨的是工作序列而不是单个工作
  • 至少要考虑到一个ViewGroup和一个View
  • 传递或者说分发包含父View向子View传递工作(工作下发进程)和子View向父View传递工作(工作消费进程)。

举例阐明一下为什么要考虑上面这几点,假如工作传到了一个没有子View的View里边,这时view的onTouchEvent会被回调,咱们能够经过重写onTouchEvent的回来值来决议是否消费这个工作。假如这个工作是down,而onTouchEvent回来false不必费它,那么工作序列后边的工作都不再分发给这个View,假如消费了down工作,那么后续工作会持续分发给这个View,这时,假如不必费后续工作的某个move工作,那么这个move工作后边的工作仍然会分发给这个View。

由此可见,对工作序列里某个工作的消费状况是会影响后续工作的分发的。

另一方面,假如这个View没消费down工作,那么会一层层往上回调父View的onTouchEvent将down工作传递给父View,所以工作的消费也是一个传递工作的进程。

举例阐明一下为什么要考虑上面这几点,假如工作传到了一个没有子View的View里边,这时view的onTouchEvent会被回调,咱们能够经过重写onTouchEvent的回来值来决议是否消费这个工作。假如这个工作是down,而onTouchEvent回来false不必费它,那么工作序列后边的工作都不再分发给这个View,假如消费了down工作,那么后续工作会持续分发给这个View,这时,假如不必费后续工作的某个move工作,那么这个move工作后边的工作仍然会分发给这个View。

由此可见,对工作序列里某个工作的消费状况是会影响后续工作的分发的。

另一方面,假如这个View没消费down工作,那么会一层层往上回调父View的onTouchEvent将down工作传递给父View,所以工作的消费也是一个传递工作的进程。

上面的比方是经过编写代码验证的一个现实,至于原因,会在文中详细剖析,这儿只为阐明需求考虑上面的几个留意点。

尽管工作体系很杂乱,可是是有规矩可循的,咱们实践的意图便是寻觅这个规矩。依据我的了解,画了一张图作为Android工作机制的一个总结:

Android工作分发流程图

由图能够看到将整个流程分为了4种状况,下面将经过实践详细剖析这4种状况,包含为什么这样区分,其他更多的状况怎么归类扫除等。

首要完成下图界面,界面每一层View的dispatchTouchEvent示例代码(https://github.com/developerzjy/ViewEventTest)。图中,咱们能够把Activity看作是尖端父View。

界面

然后研讨 Android 工作分发流程图中的4种状况:

  • 默许状况,悉数回来super,默许状况是不阻拦不必费工作的。
  • View的onTouchEvent消费down工作,其他默许。
  • ViewGroup2的onTouchEvent消费down工作,其他默许。
  • ViewGroup2的onInterceptTouchEvent阻拦down之后的工作。

消费工作指onTouchEvent回来true,阻拦工作指onInterceptTouchEvent回来true。从4种状况能够看出,将一个工作序列的ACTION_DOWN和ACTION_DOWN之后的工作分隔考虑了,剖析完源码之后就会了解为什么这样做。

消费工作指onTouchEvent回来true,阻拦工作指onInterceptTouchEvent回来true。从4种状况能够看出,将一个工作序列的ACTION_DOWN和ACTION_DOWN之后的工作分隔考虑了,剖析完源码之后就会了解为什么这样做。

下面开端结合log剖析4种状况,为了便利检查和描绘,我会把log用空行分为三部分,榜首部分是down工作,第二部分是move工作,第三部分是up工作。

状况1:默许状况,悉数回来super,默许状况是不阻拦不必费工作的。( 1955): MainActivity->dispatchTouchEvent

( 1955): MyViewGroup1-->dispatchTouchEvent

( 1955): MyViewGroup1-->onInterceptTouchEvent

( 1955): MyViewGroup2--->dispatchTouchEvent

( 1955): MyViewGroup2--->onInterceptTouchEvent

( 1955): MyView--------------->dispatchTouchEvent //down工作下发进程完毕

( 1955): MyView--------------->onTouchEvent // down工作消费进程开端

( 1955): MyViewGroup2--->onTouchEvent

( 1955): MyViewGroup1-->onTouchEvent

( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //move1工作

( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //move2工作

( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //up工作

( 1955): MainActivity->onTouchEvent

上面的log我手动加了几个注释,默许状况下Activity/ViewGroup/View不阻拦不必费工作,由log很简略看出,down工作阅历了一下一上的进程,下是分发进程,上是消费进程。假如下发无人阻拦,工作会一向向下传递到子View,假如子View不必费工作,会传给父View去消费,即依次回调父View的onTouchEvent。

然后便是move和up工作,log很简略,因为down工作子View们无人消费,那么工作序列里边的后续工作也就不再下发了,直接尖端Activity(DecorView)自己来处理。

为什么后续工作不再下发给子View,答案在源码里。接下来开端剖析源码。

下面是Vieappstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢wGroup的dispatchTouchEvent办法,只保留了要害代码,其间if句子都是完好的,能够经过if句子在完好源码中定位代码。数字编号的注释是 ACTION_DOWN工作的下发进程,留意是down工作下发进程。

publicbooleandispatchTouchEvent(MotionEvent ev){

booleanhandled = false;

if(onFilterTouchEventForSecurity(ev)) {

//1.首要假如是down工作,reset 一些状况,其间包含将mFirstTouchTarget置空

if(actionMasked == MotionEvent.ACTION_DOWN) {

cancelAndClearTouchTargets(ev);

resetTouchState;

}

//2.是否阻拦工作,用布尔变量intercepted表明

finalbooleanintercepted;

if(actionMasked == MotionEvent.ACTION_DOWN

|| mFirstTouchTarget != null) {

finalbooleandisallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

if(!disallowIntercept) {

//这儿调用onInterceptTouchEvent看是否阻拦工作

intercepted = onInterceptTouchEvent(ev);

ev.setAction(action);

} else{

intercepted = false;

}

} else{ //假如mFirstTouchTarget是空,并且当时工作不是ACTION_DOWN,就阻拦工作

//留意此处直接给intercepted赋值而没有调用onInterceptTouchEvent办法

intercepted = true;

}

// 3.得到intercepted之后,假如不阻拦,进入这个if

if(!canceled && !intercepted) {

//4.假如是down工作,进入这个if

if(actionMasked == MotionEvent.ACTIappstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢ON_DOWN

|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)

|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

//5.newTouchTarget是这个办法里边界说的,默许是空,进入这个if

if(newTouchTarget == null&& childrenCount != 0) {

//6.循环,寻觅处理工作的子View

for( inti = childrenCount - 1; i >= 0; i--) {

//7.留意这个if里边的dispatchTransformedTouchEvent办法,里边调用了子View的dispatchTouchEvent办法

// 调用子View的dispatchTouchEvent办法即把工作传给了子View去处理,

// 这时先走一遍子View里的dispatchTouchEvent逻辑并回来一个布尔值表明是否消费掉了工作,

// 假如子View的dispatchTouchEvent回来true阐明子View消费工作,进入这个if,不然没消费不进入此if

if(dispatchTransformedTouch白姐五颜六色共同图库免费Event(ev, false, child, idBitsToAssign)) {

//8.假如子View消费了工作,那么给mFirstTouchTarget赋值

// 给mFirstTouchTarget赋值的操作在addTouchTarget办法里

newTouchTarget = addTouchTarget(child, idBitsToAssign);

break;

}

}

}

}

}

//在编号7的if条件里边现已把工作下发到了子View,并得到了子View回来的成果

//至此,默许状况下发工作的逻辑完毕

//下面消费工作相关的代码,省掉

}

//终究回来成果,此办法完毕

returnhandled;

//至此,假如编号8的代码没履行,也便是子View的dispatchTouchEvent没消费工作,那么mFirstTouchTarget的值是空

//结合编号3的条件,能够得出定论:当ViewGroup不阻拦工作且它的子View消费工作的时分,mFirstTouchTarget不为空,不然mFirstTouchTarget是空。

}

代码中注释很详细,终究能够得到一个定论:当ViewGroup不阻拦down工作且它的子View消费down工作的时分,mFirstTouchTarget不为空,不然mFirstTouchTarget是空。

下面带着这个定论从头看源码,不过这次剖析的不是down工作,而是down之后的工作。只看要害部分,上面代码的编号2部分如下:

///2.是否阻拦工作,用布尔变量intercepted表明

finalbooleanintercepted;

if(actionMasked == MotionEvent.ACTION_DOWN

|| mFirstTouchTarget != null) {

finalbooleandisallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

if(!disallowIntercept) {

//这儿调用onInterceptTouchEvent看是否阻拦工作

intercepted = onInterceptTouchEvent(ev);

ev.setAction(action);

} else{

intercepted = false;

}

} else{ //假如mFirstTouchTarget是空,并且当时工作不是ACTION_DOWN,就阻拦工作

//留意此处直接给intercepted赋值而没有调用onInterceptTouchEvent办法

intercepted = true;

}

首要if里边的actionMasked == MotionEvent.ACTION_DOWN肯定是不成立了,看mFirstTouchTarget != null,假如mFirstTouchTarget不是空,那么阐明子Vie施索恩工作室w消费了down工作,会履行到intercepted = onInterceptTouchEvent(ev);这一行代码。假如mFirstTouchTarget是空,阐明子View没消费down工作,直接else里边intercepted = true;阻拦工作。然后看默许状况下的log:

( 1955): MainActivity->dispatchTouchEvent

( 1955): MyViewGroup1-->dispatchTouchEvent

( 1955): MyViewGroup1-->onInterceptTouchEvent

( 1955): MyViewGroup2--->dispatchTouchEvent

( 1955): MyViewGroup2--->onInterceptTouchEvent

( 1955): MyView--------------->dispatchTouchEvent //down工作下发进程完毕

( 1955): MyView--------------->onTouchEvent // down工作消费进程开端

( 1955): MyViewGroup2--->onTouchEvent

(appstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢 1955): MyViewGroup1-->onTouchEvent

( 1955): MainAc蛇妃带蛋跑tivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //move1工作

( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //move2工作

( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //up工作

( 1955): MainActivity->onTouchEvent

这儿尖端的ViewGroup是MainActivity(DecorView),首要down工作下发到子View,然后子View没消费它,又一层层交给父View消费,终究无人消费传回了MainActivity,down工作完毕。由上面的源码剖析可知,这时的mFirstTouchTarget是空,假如move工作来了,那么直接履行源码编号2部分的else阻拦工作,所今后续工作的log便是上面这样不再下发(一起也没有onInterceptTouchEvent办法的log因为没调用到它)。假如子View消费down工作,mFirstTouchTarget就不是空,后续工作的流程就与down相似了,读者能够修正MyView的onTouchEvent消费掉down工作试一下消费down工作的状况。

关于后续工作,无非便是阻拦不阻拦,决议权仍是在编号2部分的代码。决议的成果是是否进入编号3的if,进入的话,假如不是down工作的就直接跳出编号3的if了。

扩展:由上面的剖析可知,dispatchTouchEvent办法是由父View调用的,子View是经过这个办法的回来值来告知父View是否消费工作了,这个咱们都知道。可是,考虑一个问题,Activity -> ViewGroup1 -> ViewGroup2 -> View,假如工作按这个次序下发,终究View消费了down工作,那么Activity怎么知道View是否消费工作呢。进程必定是这样

View.dispatchTouchEvent 回来 true ->

ViewGroup2.dispatchTouchEvent 回来 true ->

ViewGroup1.dispatchTouchEvent 回来 true ->

Activity得到ViewGroup1.dispatchTouchEvent 回来 true后便是上面剖析的源码流程了。

这个进程仅仅猜想,我没有深入剖析源码,不过我打了个log,成果是一系列的dispatchTouchEvent确实是回来了true。也便是说ViewGroup1和ViewGroup2并没有消费工作,dispatchTouchEvent却回来了true,那么网上的一种说法:dispatchTouchEvent回来true便是消费工作。这种说法或许并不彻底精确,详细还需去源码找答案,这儿先不剖析了,仅仅阐明一个问题:不要容易重写dispatchTouchEvent。就算重写,也要尽量确保调用到super办法并且回来值与super成果共同。其实,源码现已供给了两个接口来直接的重写它,便是onInterceptTouchEvent和onTouchEvent,经过源码能够知道它们终究都是dispatchTouchEvent来调用的。并且用onTouchEvent的回来值来描绘是否消费工作是没有问题的(不必费工作的View底子调用不到onTouchEvent)。

针对appstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢默许状况下的log的源码剖析到此完毕,了解了默许状况,后边3种状况就简略了。

状况2:View的onTouchEvent消费down工作,其他默许

(这儿说的View是界面图里的最小的子View,不是ViewGroup1或ViewGroup2)

先剖析一下,由上面的默许状况来看,关于工作机制只研讨单个工作是不能阐明问题的,需求看整个工作序列里每个工作是怎么处理的。所以研讨工作消费需求考虑以下几种状况:

阐明一下上图,关于图中第1点不必费down工作,其实便是状况1(默许状况),由状况1的log能够看出,不必费down工作的时分,后续工作不再分发给该View,所以图中分支1关于View来说不必再考虑后续工作。

然后看图中2,3,4,5分支,经过前面的Android工作分发流程图能够看出,它们能够得出同一个定论,所以它们能够看成是一种状况。

剖析至此,只要状况1和状况2两种状况。关于2,3,4,5分支得出定论?这儿拿图中分支5来举例,修正MyView的onTouchEvent的代码如下:

int x = 0;

@Override

publicboolean onTouchEvent(MotionEvent event) {

if(event.getAction == MotionEvent.ACTION_DOWN) {

x = 0;

Log.d(TAG, "MyView--------------->onTouchEvent x="+ x);

returntrue;

}

x++;

Log.d(TAG, "MyView--------------->onTouchEvent x="+ x);

if(x == 3) {

returntrue;

}

if(x == 5) {

returntrue;

}

returnsuper.onTouchEvent(event);

}

代码不难了解,完成了MyView消费工作序列里的down工作和第3个,第5个工作(从0开端计数),其他工作都不必费。一起,为了便利检查,在log中打印出了x的值。log如下(每个工作的log用空做了爱行分隔了):

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888):吴建春简历 MyView--------------->onTouchEvent x= 0// 消费进程开端

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispa智小楠tchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888): MyView--------------->onTouchEvent x= 1// 消费进程开端

( 1888): MainActivity->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888): MyView---------------&g博伽茹蒙斯t;onTouchEvent x= 2// 消费进程开端

( 1888): MainActivity->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888): MyView--------------->onTouchEvent x= 3// 消费进程开端

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888): MyView--------------->onTouchEvent x= 4// 消费进程开端

( 1888): MainActivity->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888): MyView--------------->onTouchEvent x= 5// 消费进程开端

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTappstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢ouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent

( 1888): MyView--------------->dispatchTouchEvent // 下发进程完毕

( 1888): MyView--------------->onTouchEvent x= 6// 消费进程开端

( 1888): MainActivity->onTouchEvent

上面log总共7个工作,尽管log很长,其实很简略,首要分为两类:MyView消费的和MyView没消费的。其间x=0,3,5是消费的,其他未消费。下发进程log 中的一切工作悉数相同(和默许状况下的down工作也相同),为什么每次都会调用onInterceptTouchEvent,经过源码剖析也现已很清楚了。消费进程的规矩也很明显,x=0,3,5的工作消费掉就没了,其他没消费的工作直接传给尖端父View而不是一层层传回去。

状况3:ViewGroup2的onTouchEvent消费down工作

首要,由状况1的log能够看出(假如了解了默许状况,这时分是没必要回去翻log的,脑中天然构成),要想呈现当时的状况3,首要得让View的onTouchEvent不必费down工作(假如消费便是状况2了,现已剖析完),一起,因为View的onTouchEvent不必费down工作,那么后续工作都不再传给View,也便是说没View什么事了,所以界面相当于变成了下图这样:

看图和标题发现了什么,变成状况2了,那就简略了,直接看log,下面是ViewGroup2的onTouchEvent消费down工作,后续工作都不必费的log(相当于状况2那个图的分支2,能够趁便验证上面分支5得出的定论):

( 2008): MainActivity->dispatchTouchEvent

( 2008): MyViewGroup1-->dispatchTouchEvent

( 2008): MyViewGroup1-->onInterceptTou那书总不完毕chEvent

( 2008): MyViewGroup2--->dispatchTouchEvent

( 2008): MyViewGroup2--->onInterceptTouchEvent

( 2008): MyView--------------->dis哋哒哋patchTouchEvent

( 2008): MyView--------------->onTouchEvent

( 2008): MyViewGroup2--->onTouchEvent

( 2008): MainActivity->dispatchTouchEvent

( 2008): MyViewGroup1-->dispatchTouchEvent

( 2008): MyViewGroup1-->onInterceptTouchEvent

( 2008): MyViewGroup2--->dispatchTouchEvent

( 2008): MyViewGroup2--->onTouchEvent

( 2008): MainActivity->onTouchEvent

( 2008): MainActivity->dispatchTouchEvent

( 2008): MyViewGroup1-->dispatchTouchEvent

( 2008): MyViewGroup1-->onInterceptTouchEvent

( 2008): MyViewGroup2--->dispatchTouchEvent

( 2008): MyViewGroup2--->onTouchEvent

( 2008): MainActivity->onTouchEvent

( 2008): MainActivity->dispatchTouchEven女ht

( 2008): MyViewGroup1-->dispatchTouchEvent

( 2008): MyViewGroup1-->onInterceptTouchEvent

( 2008): MyVi活蛎肽ewGroup2--->dispatchTouchEvent

( 2008): MyViewGroup2--->onTouchEvent

( 2008): MainActivity->onTouchEvent

log中需求留意down工作阅历了一次MyView的onTouchEvent办法,down之后的工作不再履行ViewGroup2的onInterceptTouchEvent办法。原因在源码剖析中现已给出,定论在前两种状况现已得出,没什么好解说的了。

由上面剖析可知,本状况是能够算成状况2的,仅仅感觉独自把它分出来逻辑更清楚合理一些,剖析状况4的时分也会解说一些原因,一起,这也是对前两种状况的一个运用,假如了解了状况1和状况2,其他许多本文没说到的状况都能解说通的。

状况4:ViewGroup2的onInterceptTouchEvent阻拦down之后的工作

前面研讨的都是onTouchEvent消费相关的状况,这儿研讨onInterceptTouchEvent工作下发阻拦。

首要仔细看标题,为什么不考虑阻拦down工作而只考虑阻拦down之后的工作。因为阻拦down工作之后,工作直接交给本身的onTouchEvent处理,不再经过子View,也就变成了状况3的界面(留意这儿是变成状况3的界面而不是变成状况3,内部流程与状况3是有差异的,后边解说)。变成了状况3的界面之后,回调到本身的onTouchEvent又分为不必费down和消费down:不必费down便是状况1;消费down便是状况2。

这儿解说为什么 “是变成状况3的界面而不是变成状况3”,这儿的状况是ViewGroup2的onInterceptTouchEvent阻拦down之后,down直接交给ViewGroup2的onTouchEvent去消费。而状况3是没有阻拦,down工作先去子View溜了一圈,发现子View不必费它,然后才传递给父亲ViewGroup2去消费。

阐明晰有两种办法能够让ViewGroup2消费到down工作。这也是把状况3从状况2分离出来的一个原因。

这儿解说为什么 “是变成状况3的界面而不是变成状况3”,这儿的状况是ViewGroup2的onInterceptTouchEvent阻拦down之后,down直接交给ViewGroup2的onTouchEvent去消费。而状况3是没有阻拦,down工作先去子View溜了一圈,发现子View不必费它,然后才传递给父亲ViewGroup2去消费。

阐明晰有两种办法能够让ViewGroup2消费到down工作。这也是把状况3从状况2分离出来的一个原因。

上面的剖析阐明阻拦down后必定呈现前面的三种状况之一,所以这儿不再考虑阻拦down。下面看看阻拦down之后的工作会有什么不同。

修正ViewGroup2的onInte福利共享rceptTouchEvent代码如下:

intx = 0;

@Override

publicbooleanonInterceptTouchEvent(MotionEvent ev){

Log.d(TAG, "MyViewGroup2--->onInterceptTouchEvent x="+x);

if(x== 3) {

x++;

returntrue;

}

x++;

returnsuper.onInterceptTouchEvent(ev);

}

代码很简略,当x==3的时分阻拦工作,也便是阻拦工作序列里的第4个工作,log如下:

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGrou杨增和p1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent x= 0

( 1888): MyView--------------->dispatchTouchEvent

( 18钢姬铁兵漫画88): MyView--------------->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent x= 1

( 1888): MyView--------------->dispatchTouchEvent

( 1888): MyView--------------->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyView王觉彬Group2--->onInterceptToucappstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢hEvent x= 2

( 1888): MyView--------------->dispatchTouchEvent

( 1888): MyView--------------->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouappstore无法衔接,Android 工作体系全面总结+实践剖析,亡羊补牢chEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onInterceptTouchEvent x= 3

( 1888): MyView--------------->dispatchTouchEvent

( 1888): MyView--------------->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onTouchEvent

( 1888): MainActivity->onTouchEvent

( 1888): MainActivity->dispatchTouchEvent

( 1888): MyViewGroup1-->dispatchTouchEvent

( 1888): MyViewGroup1-->onInterceptTouchEvent

( 1888): MyViewGroup2--->dispatchTouchEvent

( 1888): MyViewGroup2--->onTouchEvent

( 1888): MainActivity->onTouchEvent

log需求剖析3个当地:

  • x=3之前的工作,很好了解,便是状况2。
  • x=3的时分的工作,x=3的时分ViewGroup2现已阻拦工作了,为什么MyView仍是收到了一个工作?假如用log把MyView收到的这个工作的action值打印出来的话发现它是ACTION_CANCEL这个工作,它表明非人为原因完毕本次工作。关于ACTION_CANCEL工作我举一个比方,一般咱们处理工作的时分会在down工作记载一些东西,然后在up工作清掉记载。那么假如在ListView中有一个Button,咱们按住Button的时分按钮收到down工作,这时手指开端滑动,工作就会被ListView阻拦处理了,这时分按钮就再也收不到up工作了,可是ListView阻拦工作的时分按钮全彩本会收到cancel工作表明非人为原因完毕本次工作,所以这时能够把up工作要做的工作让cancel来做。
  • x=3之后的工作,代码中只改了onInterceptTouchEvent,而onTouchEvent是默许回来,也便是说Vj小学生iewGroup2阻拦工作之后并没有消费,从log也能够看出,每个工作都传回了Activity。可是,ViewGroup2不必费工作为什么后续工作仍是不断的分发给ViewGroup2,并且履行到它的onTouchEvent办法?(看似如同违反了默许状况的规矩),这是一个问题,也是需求留意的一点。 首要,工作为什么分发到ViewGroup2?其实源码剖析中现已解说了,当有子View消费掉down工作后,(MainActivity的)mFirstTouchTarget就不再是空,后续工作都会被下发到子View(递归),除非父View的onInterceptTouchEvent自动阻拦工作,而比方中ViewGroup2的父View和Actvity并没有阻拦工作。 然后是为什么总是调到ViewGroup2的onTouchEvent办法,原因是ViewGroup2没有处理工作的子View了,所以会调用到ViewGroup2的super.dispatchTouchEvent,也便是调用父类View.dispatchTouchEvent办法,所以假如没有设置onTouc成真波hListener就必定会调用到onTouchEvent了。

文章到这儿就剖析完了,这时分再看Android工作分发流程图,此图便是依据上面4种状况画出来的,假如了解了那4种状况(至少要做到给出一种阻拦消费办法,能想到每个工作的log是什么样的),那么看懂这张图应该是不难的。

Android工作分发流程图

关于定论,这儿就不给出纯文字描绘了(即便描绘出来也是很杂乱的,一堆if),《Android开发艺术探究》中给了11条定论,有爱好的能够看一下。可是,上图中有一些文字描绘,能够当作定论,首要是绿色箭头对应的两部分,描绘的是各个工作终究的去向,图中的各个分支箭头,便是各种状况下的条件。

终究,文中有没考虑到的状况或不对的当地欢迎留言评论。别的,关于源码,文中只给出了下发进程的剖析。消费进程就不再给出详细剖析了,供给一个思路,文中的源码剖析里有一行注释 //下面消费工作相关的代码,省掉,读者能够从这儿开端看消费相关的代码,留意这是ViewGroup类里的dispatchTouchEvent,这行注释下面会有相关的逻辑调用到dispatchTransformedTouchEvent这个办法(下发进程也调到了这个办法),这个办法里会有super.dispatchTouchEvent(event)这样的代码调用到ViewGroup类的父类View里边的dispatchTouchEvent,然后看View里边的dispatchTouchEvent,就会发现onTouchEvent被调用了,一起也会发现一些其他的东西,比方onTouchListener和onTouchEvent的优先级。*

*关于dispatchTransformedTouchEvent再解说一下,里边有两种代码:super.dispatchTouchEvent(event)和child.dispatchTouchEvent(event)。简略了解,前者便是调用ViewGroup本身的onTouchEvent去消费,后者是将工作分发给(界面上的)子View去处理。假如子View是ViewGroup,那么子View处理工作的流程和父View相似,从ViewGroup的dispatchTouchEvent开端履行;假如子View不是ViewGroup,那么直接履行View的dispatchTouchEvent逻辑。而View的dispatchTouchEvent里并没有将工作传给父View去消费的代码,其实消费进程工作不是传递的,而是依据子View的dispatchTouchEvent回来值和一些ViewGroup本身的记载来决议是否调用super.dispatchTouchEvent(event)来调用本身的onTouchEvent。好了,思路就供给到这儿。

解说看到的一个问题:

问题:状况2剖析中终究一段话“消费进程的规矩也很明显,x=0,3,5的工作消费掉就没了,其他没消费的工作直接传给尖端父View而不是一层层传回去。” 这儿是为什么呢?

先看下Activity里边的dispatchTouchEvent源码

publicbooleandispatchTouchEvent(MotionEvent ev){

if(ev.getAction == MotionEvent.ACTION_DOWN) {

onUse愿望国度rInteraction;

}

if(getWindow.superDispatchTouchEvent(ev)) {

returntrue;

}

returnonTouchEvent(ev);

}

不难看出activity的onTouchEvent能否被调用取决于if条件getWindow.superDispatchTouchEvent(ev)。

早年面的源码剖析那能够知道一点:dispatchTouchEvent办法是由父View调用的,子View是经过这个办法的回来值来告知父View是否消费工作了(详细看源码剖析编号7那里,还有状况1结尾的扩展那一部分)。

所以在这个问题中,关于不必费的工作,每一层View/ViewGroup的dispatchTouchEvent回来值如下:

MyView.dispatchTouchEvent 回来 false ->

ViewGroup2.dispatchTouchEvent 回来 false ->

ViewGroup1.dispatchTouchEvent 回来 false ->

……

终究根View,DecorView.dispatchTouchEvent 回来 false

这个进程因为每个View都不必费工作,它们的onTouchEvent都没被调用到,详细的代码就不剖析了。

然后看Activity的dispatchTouchEvent源码,getWindow.superDispatchTouchEvent(ev),这个办法是Window抽象类类的办法,咱们都知道Window的完成类是PhoneWindow,所以直接看PhoneWindow的superDispatchTouchEvent办法:

publicboolean superDispatchTouchEvent(MotionEvent event) {

returnmDecor.superDispatchTouchEvent( event);

}

ctrl+左键跳到DecorView.java的superDispatchTouchEvent办法

publicboolean superDispatchTouchEvent(MotionEvent event) {

returnsuper.dispatchTouchEvent( event);

}

ctrl+左键再跳便是ViewGroup的dispatchTouchEvent办法。上面说了,关于不必费的工作,这一系列的办法都回来false,所以终究Activity的dispatchTouchEvent办法里边,if(getWindow.superDispatchTouchEvent(ev))条件是false,履行return onTouchEvent(ev);

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。