Activity的事件分發源碼分析

Activity的事件分發流程圖

在這裏插入圖片描述
dispatchTouchEvent(MotionEvent event)

onTouchEvent(MotionEvent event)

首先我們在Activity中重寫dispatchTouchEvent方法,然後點擊super.dispatchTouchEvent(ev)進入系統源碼,就是Activity的dispatchTouchEvent(MotionEvent ev)方法,來看一下它的一個分發的流程。
在這裏插入圖片描述
這一部分的內容就是它的一個源碼的實現,現在的這個源碼的版本是Android 8.0 的一個版本(圖3)。

if (ev.getAction() == MotionEvent.ACTION_DOWN)

判斷當前的事件是手指按下的時候,表示事件剛剛產生,系統就會調用onUserInteraction()方法,然後我們進入onUserInteraction()方法中(圖4),會發現默認是個空的方法,如果我們沒有對這個方法進行重寫的話,是不需要處理它的,我們可以通過重寫onUserInteraction()方法,來監聽事件的一個開始。

if (getWindow().superDispatchTouchEvent(ev))

這裏的事件交給了Activity所附屬的Window,也就是這裏的getWindow()進行派發,這個方法如果返回爲true的話,那麼Activity的dispatchTouchEvent的方法就會返回爲true,表示整個事件傳遞就結束了,而如果返回爲false的話,就會執行到(圖3的4),就會調用Activity的onTouchEvent方法。

在這裏插入圖片描述在這裏插入圖片描述

源碼解析:getWindow().superDispatchTouchEvent(ev)

在Activity裏面getWindow()是獲取一個Window對象,對於Window對象來說,它本身是一個抽象類(abstract),而我們的superDispatchTouchEvent方法也是一個抽象的方法,我們在Activity裏面調用window下面的superDispatchTouchEvent方法,就是一個抽象方法,那這個方法的實現在哪呢?

看圖5(這個抽象類的唯一的實現類是android.view.PhoneWindow)。所以說Window裏面的superDispatchTouchEvent方法,它的實現在PhoneWindow裏面。

在圖6中,可以知道PhoneWindow是直接調用mDecor.superDispatchTouchEvent(event)方法,而這個mDecor,是window所持有的一個DecorView對象,所以PhoneWindow裏面superDispatchTouchEvent的實現,就是調用了DecorView裏面的一個superDispatchTouchEvent方法。而這個DecorView是Activity下的一個最頂層的View(圖7),它繼承至FrameLayout。

在DecorView(圖8)中,可以看到,其實它是調用了父類的dispatchTouchEvent方法,而它的父類就是FrameLayout(圖9),而FrameLayout的父類就是ViewGroup(圖10),對於FrameLayout來說,它本身是沒有dispatchTouchEvent方法的,這個方法的實現其實是在ViewGroup裏面(圖11)。

所以getWindow().superDispatchTouchEvent(ev)的返回值,就是ViewGroup裏面dispatchTouchEvent方法的返回值,當這個返回值爲true的時候,DecorView的superDispatchTouchEvent方法返回值也是true,然後返回到PhoneWindow裏面,它的superDispatchTouchEvent方法的返回值是直接用了DecorView下面的superDispatchTouchEvent方法的返回值,所以說這個返回值會直接返回到Activity的(圖3的3)的位置。

當返回值是true的時候,表示當前事件被消費了,也就不會調用Activity的onTouchEvent方法。

當返回值是false的時候,表示當前事件沒有被消費,當前的任何視圖都未能處理掉這個觸摸的事件,這個時候纔會調用Activity的onTouchEvent方法,並且把Activity的onTouchEvent返回值作爲Activity的dispatchTouchEvent方法的返回值。

說下Activity、Window、PhoneWindow、DecorView的關係

每一個Activity都持有一個Window對象,而Window本身是一個抽象類,它有一個唯一的實現類就是PhoneWindow,也就是說在Activity裏面所持有的Window對象就是PhoneWindow。對於PhoneWindow來說,它本質上是一個窗口,並不具備太多View視圖相關的功能,PhoneWindow又持有一個DecorView實例,這個DecorView就是Activity最頂層的View,DecorView繼承至FrameLayout,當我們在Activity的onCreat方法裏面去調用setContentView的時候,傳入的layout其實就是添加到了DecorView上面,對於DecorView來說它就是Activity最頂層的View。

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

源碼解析 onTouchEvent(MotionEvent event)方法

Activity的onTouchEvent的實現方法(見圖12),首先進行一個判斷,當mWindow.shouldCloseOnTouch(this, event)方法返回true的時候,就會關閉掉當前這個Activity,然後返回爲true,也就是onTouchEvent方法返回值爲true,表示已經消耗掉了這個事件,否則就返回爲false。

然後我們看下mWindow.shouldCloseOnTouch方法(見圖13),

mCloseOnTouchOutside :爲true時,表示當前的Activity支持點擊空白部分讓Activity進行消失的,這個變量一般在Activity以Dialog的形式去進行呈現的時候纔會爲true。

當 peekDecorView() !=null 的時候,也就是PhoneWindow下面的DecorView不爲null的時候。

peekDecorView是一個抽象方法(見圖14),它的實現在PhoneWindow裏面(見圖15),這個方法返回的是當前的DecorView。

也就是說 peekDecorView() !=null ,表示我們當前這個Window下面是持有DecorView的時候。

isOutside爲true的時候,表示當前的點擊事件是在Window所持有的DecorView之外的,表示整個點擊事件沒有點擊到DecorView裏面。

當mCloseOnTouchOutside && peekDecorView() !=null && isOutside 條件都滿足的時候,這個方法纔會返回爲true,然後mWindow.shouldCloseOnTouch纔會返回爲true,就會關閉掉當前這個Activity,然後消費掉這個事件,否則就會返回爲false,然後Activity的onTouchEvent的返回值就會作爲Activity的dispatchTouchEvent的返回值返回回去。

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章