開頭
25歲那年,我從京東離職,入職百度。
在百度認識了當時的架構師久哥(T9級別),因為他的一番話,徹底改變了我的職業生涯,短短三年的時間,我從一枚普通程序員成長為別人眼中的技術大咖。
當時因為業務需要,也承蒙久哥照顧,他跟我說過這樣一段話:
他問,“如果用5年的時間學習數據庫,你能不能成為這個領域的專家?”
我說,“應該可以吧”
他說,“你現在25,5年后也才30,30歲就能成為某個領域的專家,為什么不去做呢?你看看周圍有多少30歲的人還一事無成,而那個時候的你已經是數據庫專家了。”
當時的我,剛剛進入別人夢寐以求的BAT,處于各種浮躁的時期,雖然每天也在學習,看起來也很努力,但是效果極其有限,今天想學大數據,明天想學云計算,后天又要研究機器學習,心境變化無常,不知道自己未來究竟該是什么樣。
面試官:說說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是如何分發的?
新的開始
改變人生,沒有什么捷徑可言,這條路需要自己親自去走一走,只有深入思考,不斷反思總結,保持學習的熱情,一步一步構建自己完整的知識體系,才是最終的制勝之道,也是程序員應該承擔的使命。
如果有需要進階Android高級工程師系統學習資料的,我可以免費分享給大家,需要完整版的朋友,【點這里可以看到全部內容】。
《系列學習視頻》
《系列學習文檔》
《我的大廠面試之旅》
》**
[外鏈圖片轉存中…(img-t7ok84Nc-1621871216486)]
《我的大廠面試之旅》
[外鏈圖片轉存中…(img-c2wn0NDd-1621871216490)]