Android事件分發機制一:事件是如何到達activity的?

事件分發,真的必定從Activity開始嗎?java

前言

很高興碰見你~android

事件分發,android中一個老生常談的話題了。基本的流程咱們也都知道是從Activity開始分發,但有一個關鍵問題是:事件是如何到達Activity的git

你覺得我接下來要開始講源碼、系統底層了?不不不,本文不講這些。咱們要探究的是,一個觸摸信息從系統底層產生以後,是如何一步步到達目標view的。api

本文是筆者android觸摸事件系列文章的開篇,主要的內容是分析觸摸事件傳遞的路徑。不會糾結於源碼與底層,而是把觸摸事件來源的大致流程呈現出來,便於對事件分發體系有個更加完整的理解。框架

管理單位:window

android的view管理是以window爲單位的,每一個window對應一個view樹。Window機制不只管理着view的顯示,也負責view的事件分發。關於window的本質,能夠閱讀筆者的另外一篇文章window機制。研究事件分發的來源,須要從window機制入手。佈局

因此,首先要了解一個概念:view樹。post

咱們的應用佈局,通常是有多層viewGroup和view的嵌套,以下圖:學習

image

而他們對應的結構關係以下圖所示spa

image

此時,咱們就能夠稱該佈局是以一個LinearLayout爲根的一棵view樹。LinearLayout能夠直接訪問FrameLayout和RelativeLayout,由於他們都是LinearLayout的子view,一樣的RelativeLayout能夠直接訪問Button。3d

每一棵view樹都有一個根,叫作ViewRootImpl ,他負責管理這整一棵view樹的繪製、事件分發等。因此能夠說,事件分發是從viewRootImpl開始的。

咱們的應用界面通常會有多個view樹,咱們的activity佈局就是一個view樹、其餘應用的懸浮窗也是一個view樹、dialog界面也是一個view樹、咱們使用windowManager添加的view也是一個view樹等等。最簡單的view樹能夠只有一個view。

android中view的繪製和事件分發,都是以view樹爲單位。每一棵view樹,則爲一個window 。系統服務WindowManagerService,管理界面的顯示就是以window爲單位,也能夠說是以view樹爲單位。而view樹是由viewRootImpl來負責管理的,因此能夠說,wms(WindowManagerService的簡寫)管理的是viewRootImpl。以下圖:

window機制

對上圖作個簡單解釋。

  • wms是運行在系統服務進程的,負責管理全部應用的window。應用程序與wms的通訊必須經過Binder進行跨進程通訊。
  • 每一個viewRootImpl在wms中都有一個windowState對應,wms能夠經過windowState找到對應的viewRootImpl進行管理。

瞭解window機制,跟事件分發有什麼關係呢?咱們要知道,window機制管理的,不只是view的顯示邏輯,事件分發也是其中的一個重要部分。瞭解window機制的一個重要緣由是:事件分發並非由Activity驅動的,而是由系統服務驅動viewRootImpl來進行分發 ,甚至能夠說,在框架層角度,和Activity沒有任何關係。這將有助於咱們對事件分發的本質理解。

那麼觸摸信息是如何一步步到達viewRootImpl、viewRootImpl如何對觸摸信息進行分發處理的呢,這是咱們接下來要討論的。

觸摸信息是如何到達viewRootImpl的?

咱們都知道的是,在咱們手指觸摸屏幕時,即產生了觸摸信息。這個觸摸信息由屏幕這個硬件產生,被系統底層驅動獲取,交給Android的輸入系統服務:InputManagerService,也就是IMS。

IMS會對這個觸摸信息進行處理,經過WMS找到要分發的window,隨後發送給對應的viewRootImpl。因此發送觸摸信息的並非WMS,WMS提供的是window的相關信息。

這一部分涉及到系統底層的邏輯,不是本文的重點,感興趣的讀者推薦閱讀gityuan博主的文章Input系統-事件處理全過程。這裏不展開講解。大致的過程以下圖:

事件是如何到達viewRootImpl

當viewRootImpl接收到觸摸信息時,也正是應用程序進程事件分發的開始。

viewRootImpl是如何分發事件的?

前面咱們講到,viewRootImpl管理一棵view樹,view樹的最外層是viewGroup, 而viewGroup繼承於view。所以整一棵view樹,從外部能夠看作一個view。viewRootImpl接收到觸摸信息以後,通過處理以後,封裝成MotionEvent對象發送給他所管理的view,由view本身進行分發。

前面咱們講到,view樹的根節點能夠是一個viewGroup,也能夠是一個單獨的view,所以,這裏的派發就會有兩種不一樣的方式:直接給view進行處理 or viewGroup進行事件分發。viewGroup繼承自view,view中有一個方法用於分發事件:dispatchTouchEvent 。子類可重寫該方法來實現本身的分發邏輯,ViewGroup重寫了該方法。

咱們的應用佈局界面或者dialog的佈局界面,頂層的viewGroup爲DecorView,所以會調用DecorView的 dispatchTouchEvent 方法進行分發。DecorView重寫了該方法,邏輯比較簡單,僅僅作了一個判斷:

DecorView.java api29
public boolean dispatchTouchEvent(MotionEvent ev) {
    final Window.Callback cb = mWindow.getCallback();
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
  1. 若是window callBack對象不爲空,則調用callBack對象的分發方法進行分發
  2. 若是window callBack對象爲空,則調用父類ViewGroup的事件分發方法進行分發

而Activity實現了Window.CallBack接口,並在建立佈局的時候,把本身設置給了DecorView,所以在Activity的佈局界面中,DecorView會把事件分發給Activity進行處理。同理,在Dialog的佈局界面中,會分發給實現了callBack接口的Dialog。

而若是頂層的viewGroup不是DecorView,那麼對調用對應view的dispatchTouchEvent方法進行分發。例如,頂層的view是一個Button,那麼會直接調用Button的 dispatchTouchEvent 方法;若是頂層viewGroup子類沒有重寫 dispatchTouchEvent 方法,那麼會直接調用ViewGroup默認的 dispatchTouchEvent 方法。

總體的流程以下圖:

viewRootImpl對事件的分發流程

  1. viewRootImpl會直接調用管理的view的 dispatchTouchEvent 方法,根據具體的view的類型,調用具體的方法。
  2. view樹的根view多是一個view,也多是一個viewGroup,view會直接處理事件,而viewGroup則會進行分發。
  3. DecorView重寫了 dispatchTouchEvent 方法,會先判斷是否存在callBack,優先調用callBack的方法,也就是把事件傳遞給了Activity。
  4. 其餘的viewGroup子類會根據自身的邏輯進行事件分發。

所以,觸摸事件必定是從Activity開始的嗎?不是,Activity只是其中的一種狀況,只有Activity本身負責的那一棵view樹,才必定會到達activity,而其餘的window,則不會通過Activity。觸摸事件是從viewRootImpl開始,而不是Activity。

總結

最後咱們對整個流程進行一次回顧:

總體流程

  1. IMS從系統底層接收到事件以後,會從WMS中獲取window信息,並將事件信息發送給對應的viewRootImpl
  2. viewRootImpl接收到事件信息,封裝成motionEvent對象後,發送給管理的view
  3. view會根據自身的類型,對事件進行分發仍是本身處理
  4. 頂層viewGroup通常是DecorView,DecorView會根據自身callBack的狀況,選擇調用callBack或者調用父類ViewGroup的方法

到這裏,雖然觸摸事件的「去脈」咱們還不清楚,可是他的「來龍」就已經很是清晰了。後續Activity、Dialog等callBack,viewGroup,其餘頂層ViewGroup對象如何對觸摸事件進行處理,我將會在下一篇文章進行分析。

事件分發的來源遠沒有這麼簡單,源碼的細節有很是多的內容值得咱們去學習,而本文只是把總體的流程抽了出來。這裏對於有興趣讀者推薦一本書:《深刻理解android卷Ⅲ》。

感謝閱讀,但願文章對你有幫助!

全文到此,原創不易,以爲有幫助能夠點贊收藏評論轉發。
筆者才疏學淺,有任何想法歡迎評論區交流指正。
如需轉載請評論區或私信交流。

另外歡迎光臨筆者的我的博客:傳送門

相關文章
相關標籤/搜索