Android事件分發機制原始碼分析

來源:互聯網
上載者:User

標籤:原始碼   整理   事件分發   ext   自身   stat   jsb   習慣   計算   

小小感慨一下,做android有一段時間了,一直以來都是習慣整理筆記存到有道筆記上,沒有寫部落格的習慣。

以後逐步分類整理出來,也算“複習”一遍了 - _ - 。

 

android的事件分發相關的方法有三個:

    1.public booleandispatchTouchEvent(MotionEvent ev)

    2.public boolean onInterceptTouchEvent(MotionEvent ev)

    3.public booleanonTouchEvent(MotionEvent event)                           

第一個方法表示是否分發事件,第二個方法表示是否攔截事件(只ViewGroup有這種方法。View沒有) ,第三個方法表示是否消費事件。

分析原始碼之前,我們先總結一下事件分發的規律,或者說上面3個方法的用法:

    ①當TouchEvent發生時,首先Activity將TouchEvent傳遞給最頂層的View,通常是一個ViewGroup。

TouchEvent最先到達最頂層 view 的 dispatchTouchEvent ,然後由  dispatchTouchEvent 方法進行分發。返回true則不分發。所有事件都交給dispatchTouchEvent 處理。假設dispatchTouchEvent返回 false 。則view以及它的子view都接收不到興許事件,假設調用super.dispatchTouchEvent,則交給interceptTouchEvent 處理。

    ②假設 interceptTouchEvent 返回 true ,也就是攔截掉了。則興許事件交給它的 onTouchEvent 來處理interceptTouchEvent 不再處理(假設手拿起來在又一次點擊,down事件還會走一次,後面的move和up不走了)。假設onTouchEvent不處理,事件原路返回。興許事件就不交給這個view了,假設 interceptTouchEvent 返回 false 或者調用super.interceptTouchEvent ,那麼興許事件仍然經過interceptTouchEvent 處理,可是不經過onTouchEvent。

沒有interceptTouchEvent方法的普通view不考慮這種方法,其它規律同樣

    ③對於onTouvhEvent返回true表示消費事件,false表示不消費,調用super.onTouchEvent時分兩種情況,對於ViewGroup等能夠放子View的來說不消費事件,對於不能放子View的View來說消費事件。不消費事件時事件到達最底層的view後會回傳,僅僅走onTouchEvent,可能被上層View消費

假設你不過關心這幾個方法的使用。然後自己自己定義view。那看到這裡應該就沒神馬問題了。反正我知道這幾個方法會對事件分發造成什麼影響了。至於為啥我就不關心了

可是作為一個積極學習高素養的程式員來說,我們不僅要弄明確怎麼用。還要明確為什麼會出現這些情況(此處應有掌聲)。我們就依照上面的三點逐點分析。

 

    首先我們看第一點:dispatchTouchEvent。

這種方法返回false表示事件不分發,那麼能夠理解為這個view以及子view都不會消費事件。那興許事件就不會在給你了,反正給了你你也不消費嘛。幹嘛還給你,這個非常好理解,代碼實現是把全部消耗事件的View都儲存起來,所以不消費事件的View是不會即受到興許事件的,這部分代碼沒貼出來,參見ViewGroup代碼的第2213行調用addTouchTarget方法的代碼。依照常規來想。既然返回false表示不消費事件,那麼返回true就應該是消費事件了吧?NO NO NO,too young to simple。

假設你寫demo試試就會發現dispatchTouchEvent方法一直走,可是事件卻沒有分發下去,子view收不到事件,僅僅有返回值是super.dispatchTouchEvent才幹把事件分發下去。。。

納尼,這是什麼鬼。不按套路出牌啊。好吧,這樣的情況僅僅能翻原始碼了。我們以android6.0(API Level 23)的原始碼為準進行分析。

以下這段代碼是摘自ViewGroup的dispatchTouchEvent方法。在2167行是取到第i個子view。然後到2197行,這裡調用了一個方法,將上面取到的第i個子view作為參數之中的一個傳了過去。

以下這段代碼是剛才說到的在dispatchTouchEvent中調用的這種方法,看第2553行,當child不為空白的時候,調用了child的dispatchTouchEvent(詳細會走到2553或者2575行。他們本質上是一樣的,差別就是對傳過來的MotionEvent進行了一個split操作,詳細做了啥沒去深究。

有知道它們差別的小夥伴能夠留言賜教)。

到這裡是不是有一種豁然開朗的感覺呢?ViewGroup之所以能將事件分發給子view是由於在dispatchTouchEvent中又調用了子view的事件分發方法,假設你在ViewGroup的dispatchTouchEvent方法中僅僅返回true而不返回super.dispatchTouchEvent,那麼子view的事件分發的方法將不會調用。子view就拿不到事件。明確了吧,我認為我說的還是挺清楚的。中間我們忽略了其它不相關的代碼。假設你想深入瞭解,能夠再去閱讀一下原始碼,看完部落格閱讀原始碼,一切so easy~。

以下的這種方法後面還要用到。dispatchTouchEvent方法中多次調用了這種方法。

    再看第二點onInterceptTouchEvent方法:這種方法表示是否攔截事件。假設返回true。那麼事件會直接交給自身的onTouchEvent處理。為什麼會這樣呢?看以下的代碼塊:

第2104行,按下手機螢幕,走到這裡,2106行,這裡的disallowIntercept預設的情況下這裡得到的是false的(預設初始化出來的值計算),會走到2108行,調用onInterceptTouchEvent,假設我們複寫這種方法返回true,這是intercept的值就是true,再往下走會走到2238行。這時候mFirstTouchTarget是為null的。會走到2240。這裡又調用了dispatchTransformedTouchEvent方法,也就是本文中的第二個代碼塊。這時候第三個參數child是null,方法會走到2547或者2566行(詳細是哪一個。whatever)。然後調用了父類的dispatchTouchEvent方法。我們再去看父類的方法:

看到紅框框中的代碼了沒,直接調用了onTouchEvent。所以假設你的onInterceptTouchEvent返回true時會調用自身的onTouchEvent,事件就傳到自己的onTouchEvent了。

 

第三點,為啥事件不消費時會回傳給父view,我有點詞窮了。

。。

不知道該怎樣描寫敘述,原因就是遞迴。父View傳遞事件的時候是遞迴調用disPatchTouchEvent。當事件沒有被子View消費時。就會調用自己的onTouchEvent方法,所以從日誌看起來的效果就是事件被回傳回去了。

 

 

關於自己對這方面的理解。整體上就這麼多。原始碼的解析不太具體,就大概理出來了個初步的條理,可能理解的存在問題甚至錯誤,歡迎指正。

 

Android事件分發機制原始碼分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.