# Android View的事件分發 分析源碼

引言

從Android底層開始分析View的事件分發至上層FrameWork。

分兩部分來說:

  • 觸碰屏幕傳遞事件至當前Activity.
  • Activtiy傳遞事件至觸碰到的View 或者 ViewGroup

觸碰屏幕傳遞事件至當前Activity

觸摸事件是由Linux內核的一個Input子系統來管理的(InputManager),Linux子系統會在 /dev/input/ 這個路徑下創建硬件輸入設備節點(這里的硬件設備就是我們的觸摸屏了)。當手指觸動觸摸屏時,硬件設備通過設備節點像內核(其實是InputManager管理)報告事件,InputManager 經過處理將此事件傳給 Android系統的一個系統Service,這個Service叫WindowManagerService。之后WindowManagerService會將事件傳遞到PhoneWindow.

可以參考下圖, WindowManagerService連接PhoneWindow的過程.

Touch.jpg

WindowManagerService調用dispatchPointer()從存放WindowState的z-order順序列表中找到能接收當前touch事件的 WindowState,通過IWindow代理將此消息發送到IWindow服務端(IWindow.Stub子類),這個IWindow.Stub屬于ViewRoot(這個類繼承Handler,主要用于連接PhoneWindow和WindowManagerService),所以事件就傳到了ViewRoot.dispatchPointer()中.

看下ViewRoot.dispatchPointer method

ViewRoot_dispatchPointer.jpg

你可以看到通過用Message將DISPATCH_POINTER事件發送出去,處理事件應該在handleMessage method里.

看下ViewRoot.handleMessage method

ViewRoot_handleMessage.jpg

看下ViewRoot.deliverPointerEvent method

ViewRoot_deliver.jpg

最終你會發現調用mView.dispatchTouchEvent(event)
(mView是一個PhoneWindow.DecorView對象),PhoneWindow.DecorView繼承FrameLayout(FrameLayout繼承ViewGroup,ViewGroup繼承自View),DecorView里的dispatchTouchEvent方法如下. 這里的Callback的cb其實就是Activity的attach()方法里的設置回調。

看下PhoneWindow.DecorView dispatchTouchEvent method

DecprdView_dispatchTouchEvent.jpg

回調cb就代表Activity,回調會在Activity的onAttach的時候進行設置.

Activity_onAttach.jpg

再看cb執行dispatchTouchEvent method.即執行Activity的dispatchTouchEvent,之后Activity會把事件又重新傳遞到DecorView,然后會調用父類(ViewGroup)的dispatchTouchEvent 將事件傳給父類處理。即調用ViewGroup 和 View的事件分發機制。

總算繞回到View ViewGroup的事件分發機制。


View 或者 ViewGroup的事件分發機制

事件的概念

在Android中,事件主要包括點按、長按、拖拽、滑動等,點按又包括單擊和雙擊,另外還包括單指操作和多指操作。所有這些都構成了Android中的事件響應。

事件分為三種:

  • 按下(ACTION_DOWN)
  • 移動(ACTION_MOVE)
  • 抬起(ACTION_UP)

ViewGroup和View的分發

相關函數:

  • ViewGroup

    1. public boolean dispatchTouchEvent(MotionEvent event)
    2. public boolean onTouchEvent(MotionEvent event)
    3. public boolean onInterceptTouchEvent(MotionEvent event)
  • View

    1. public boolean dispatchTouchEvent(MotionEvent event)
    2. public boolean onTouchEvent(MotionEvent event)

ViewGroup和View的事件分發是向下傳遞的,即ViewGroup會一層層向子View分發事件,直到消費事件或者被丟棄。由此可以看出ViewGroup和View相關函數的返回類型都是Boolean,可以直到Boolean類型決定了某一事件是否是繼續往下傳,還是被攔截了,或是被消費了。

ViewGroup和View的相關函數都接受參數MotionEvent類型的參數,MotionEvent繼承于InputEvent,用于標記各種動作事件。之前提到的ACTIONDOWN、ACTIONMOVE、ACTION_UP都是MotinEvent中定義的常量。我們通過MotionEvent傳進來的事件類型來判斷接收的是哪一種類型的事件。

ViewGroup繼承View,即ViewGroup是一個特殊的View,ViewGroup在事件分發中比View多一個函數, onInterceptTouchEvent函數(攔截事件的函數),顧名思義,就是在ViewGroup一層就將事件攔截下來進行處理。

所以一共是三個函數,我們來總結下三個函數的功能:

  • dispatchTouchEvent方法用于事件的分發,Android中所有的事件都必須經過這個方法的分發,然后決定是自身消費當前事件還是繼續往下分發給子控件處理。返回true表示不繼續分發,事件沒有被消費。返回false則繼續往下分發,如果是ViewGroup則分發給onInterceptTouchEvent進行判斷是否攔截該事件。

  • onTouchEvent方法用于事件的處理,返回true表示消費處理當前事件,返回false則不處理,交給子控件進行繼續分發。

  • onInterceptTouchEvent是ViewGroup中才有的方法,View中沒有,它的作用是負責事件的攔截,返回true的時候表示攔截當前事件,不繼續往下分發,交給自身的onTouchEvent進行處理。返回false則不攔截,繼續往下傳。這是ViewGroup特有的方法,因為ViewGroup中可能還有子View,而在Android中View中是不能再包含子View的(iOS可以)。

流程簡述:

1.ViewGroup執行dispatchTouchEvent進行分發事件,可以進行攔截或者向下分發給子View。如果攔截事件則執行自己的onTouchEvent。
2.子View接受到事件執行dispatchTouchEvent,在這之中如果設置了Listener監聽器,則先執行onTouch方法,然后執行onTouchEvent方法。
然后事件被消費結束。

補充如果子View的Listener監聽器重寫的onTouch方法返回true,則不會繼續執行onTouchEvent方法,如果返回false則表示沒有消費結束,繼續執行onTouchEvent方法。


總結

  • 底層將觸摸事件傳遞到上層的Activity,Activity再傳遞到ViewGroup,ViewGroup攔截或者不攔截,不攔截則傳遞分發到子View進行消費,如果這個事件一直沒被消費則自動被丟棄。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容