先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
正文
注:原文来自掘金作者xiangcman
写这篇文章其实是有原因的,说实话这次面试真的很失败,看着身边的人都拿到了高薪的工资,感觉自己还是有些惭愧。也更说明自己在很多方面的知识点还是不够扎实,于是再一次拿起了view的事件分发的源码给看了一遍。
面试官:说说view中的事件分发?
android中事件分发机制是android中常见的问题,一般大家都知道view的分发事件是从view的Viewgroup(Parent)#dispatchTouchEvent
到Viewgroup(Parent)#onInterceptTouchEvent
再到View#dispatchTouchEvent
,然后到view的onTouchEvent
,最后又回到了Viewgroup(Parent)#onTouchEvent
。如果大家记不住方法名,可以直接说先是parent的分发到拦截再到view的分发,再到view的消费,最后到parent的消费
viewgroup分发
这样回答肯定是很浅显的,因为没有说出是否拦截、是否分发、是否消费的各种条件,没有涉及到各种action的分发情况,上面说的默认分发只是针对action_down的,因为view/viewgroup
各种super调用都是不进行分发、拦截、消费的,所以在没找到处理touch事件的view时候,是一直往上层view传递的,一直传到activity里面,下面我们再来整理一下:
如果viewgroup不进行分发,那么
action_down
、action_move
和action_up
只会执行到viewgroup的dispatchTouchEvent
,不分发的条件是dispatchTouchEvent
直接返回true或false,true和false的区别是true会执行action_down
、action_move
和action_up
,而如果直接返回false只会执行到action_down。并且后续的viewgroup的onInterceptTouchEvent
后续方法都不会被执行到。
关于为什么view/Viewgroup的dispatchTouchEvent
返回true的时候三个action都能执行到,而返回false的话,只能执行到action_down,这个需要到view/Viewgroup的父类中dispatchTouchEvent
找答案,该方法中会在action_down的时候调用dispatchTransformedTouchEvent
方法,而该方法是通过子view的dispatchTouchEvent方法的返回值来决定父类的dispatchTransformedTouchEvent
方法的返回值,而dispatchTransformedTouchEvent
的返回值会决定mFirstTouchTarget
是否为空,所以在action_down的过程中实际中通过子view的dispatchTouchEvent
方法返回值来确定mFirstTouchTarget
是否为空。这里贴出viewgroup中dispatchTransformedTouchEvent
方法的删减代码:
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
//省略了cancel部分的代码
//如果child为空,直接调用自己的dispatchTouchEvent方法,此时自己就相当于一个view,touch事件走自己的
if (child == null) {
handled = super.dispatchTouchEvent(transformedEvent);
} else {
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
//返回值直接通过孩子来获取返回值
handled = child.dispatchTouchEvent(transformedEvent);
}
transformedEvent.recycle();
return handled;
}
复制代码
所以如果view/viewgroup的dispatchTouchEvent
方法返回false,表示在action_down的时候,父类的dispatchTransformedTouchEvent
方法返回false;如果返回true会调用addTouchTarget
方法,给mFirstTouchTarget
设置值:
private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
target.next = mFirstTouchTarget;
mFirstTouchTarget = target;
return target;
}
复制代码
紧接着在在后面又会调用了:
这句只有在view/viewgroup的dispatchTouchEvent
返回false的时候,才会走这里,所以后面的action_move
和action_up
都会走这里,而此时传入的child=null,从上面代码可以看到,直接调用了父类的dispatchTouchEvent
方法。所以从这里不难看出在view/viewgroup的dispatchTouchEvent
返回false的时候直接调用了父类的dispatchTouchEvent
方法,因此只有action_down事件。
面试官:如果我只想有view的拖拽事件,而不想要view的点击事件,让你重写这个view的拖拽怎么设计
其实这道题考察大家对view的dispatchTouchEvent和view的onTouchEvent事件的处理流程,上面已经分析了想要view能执行到view的touch事件,那么必须要求view的dispatchTouchEvent
返回true,而dispatchTouchEvent
返回true要么是dispatchTouchEvent
直接返回true或者view的onTouchEvent
返回true。如果从效率上看,直接将dispatchTouchEvent
返回true就ok,而不需要再去关心onTouchEvent
方法。
viewgroup拦截
关于拦截无非就是拦截或不拦截,而拦截的条件是返回true,不拦截是返回false或返回super.onInterceptTouchEvent,默认的super是返回false的,因此可以用super表示不拦截
viewgroup拦截实际是通过在dispatchTouchEvent
方法中,设置intercepted变量,如果在拦截方法里面返回true,那么intercepted为true,如果为true则在action_down的时候mFirstTouchTarget=null,那么此时是直接调用dispatchTransformedTouchEvent
传入的child=null,因此将事件交给了super.dispatchTouchEvent
,此时把它当成一个view来处理了。
面试官:有个viewgroup,里面有个view,如果view在dispatchTouchView中不分发事件,并且只在action_move中拦截touch事件向下分发,说说viewgroup到view的各个action是如何分发的?
分析
先贴出事例代码:
testView在testViewgroup里面,testViewgroup在action_move的时候拦截(onInterceptTouchEvent在move返回true),testView不进行分发(dispatchTouchEvent返回true) 咋们通过log来看结果:
这里执行到TestViewgroup#dispatchTouchEvent的action_move之后就执行了TestView#dispatchTouchEvent的action_cancel,然后后面执行TestViewgroup#dispatchTouchEvent和TestViewgroup#onTouchEvent的action_move和action_up。 从前面viewgroup的dispatchTouchEvent分析知道,如果viewgroup在action_down中发现有子view的dispatchTouchEvent返回true,则mFirstTouchTarget
不为空,紧接着在action_move的时候进行了拦截,则intercepted=true,既然在move过程中确定了intercepted=true,mFirstTouchTarget不为空,则可以看viewgroup.dispatchTouchEvent部分代码:
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
//alreadyDispatchedToNewTouchTarget=false
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
//由于move过程中intercepted=true,则cancelChild=true
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
//看到了没这里就是触发child的dispatchTouchEvent的action_cancel
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
if (predecessor == null) {
//由于next=null,因此mFirstTouchTarget=null,所以在action_move刚进来的时候mFirstTouchTarget=null了,
//待会我们通过反射看下该变量
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
建议
当我们出去找工作,或者准备找工作的时候,我们一定要想,我面试的目标是什么,我自己的技术栈有哪些,近期能掌握的有哪些,我的哪些短板 ,列出来,有计划的去完成,别看前两天掘金一些大佬在驳来驳去 ,他们的观点是他们的,不要因为他们的观点,膨胀了自己,影响自己的学习节奏。基础很大程度决定你自己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。
-
无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!!!!!!!
-
准备想说怎么样写简历,想象算了,我觉得,技术就是你最好的简历
-
我希望每一个努力生活的it工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。
-
有什么问题想交流,欢迎给我私信,欢迎评论
【附】相关架构及资料
内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
vip204888 (备注Android)**
[外链图片转存中…(img-zxhrAwVr-1713325398492)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!