一張圖看清Android事件傳遞機制

一、引言

總覺得知識必須要總結(jié),不然就算再熟悉的東西,一段時間不接觸就容易遺忘;上次給一個朋友解釋回調(diào)的時候就有深刻的體會,所以現(xiàn)在養(yǎng)成總結(jié)的習(xí)慣,而我覺得最直觀的方法就是圖解,所以就有了下面的圖,通過這張圖看透Android事件傳遞機制;
PS:有時候自己的理解可能也存在問題,所以通過這種形式能夠得到大家的審查和修改意見,在這里先謝謝大家了!


二、就是這張圖(這張圖如果看不清楚,復(fù)制或保存本地,使用圖片查看器放大查看;或者點擊鏈接查看原圖)

查看高清原圖:一張圖看透Android事件傳遞機制


三、圖片局部細節(jié)詳解

1.Touch事件的傳入 :

開始由UserActivity(用戶自定義的Activity)接收到事件,這個類繼承自Activity,沒有onInterceptTouchEvent方法(為什么沒有?誰能給我一個合理的解釋嗎?)
事件傳遞到disPatchTouchEvent,這里默認的是調(diào)用父類的disPatchTouchEvent,查看父類的源碼可以看到

/**
 * Called to process touch screen events.  You can override this to
 * intercept all touch screen events before they are dispatched to the
 * window.  Be sure to call this implementation for touch screen events
 * that should be handled normally.
 * 
 * @param ev The touch screen event.
 * 
 * @return boolean Return true if this event was consumed.
 */
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    return onTouchEvent(ev);
}

這里的第一個判斷條件中方法的執(zhí)行為為空實現(xiàn):
第二個判斷中的判斷條件是有窗體事件分配決定的,窗體默認的事件分發(fā)機制,再往里面看,如下代碼

/**
 * Used by custom windows, such as Dialog, to pass the touch screen event
 * further down the view hierarchy. Application developers should
 * not need to implement or call this.
 *
 */
public abstract boolean superDispatchTouchEvent(MotionEvent event);

可以理解為Android系統(tǒng)自己定義的事件分發(fā)機制,上面說明了應(yīng)用開發(fā)者不需要去實現(xiàn)或者調(diào)用這個方法。我理解的是系統(tǒng)已經(jīng)為你準備好了普通窗口事件該如何分發(fā),不需要你再手動去修改這塊代碼了!如果你不按照我的方法來做,那么好吧,后面的事你都自己干吧,就是這么任性。所以在UserActivity中手動修改dispatchTouchEvent方法的返回值,就會使本次事件被消費掉,不再向里層傳遞。
順帶看看onTouchEvent方法吧:

/**
 * Called when a touch screen event was not handled by any of the views
 * under it.  This is most useful to process touch events that happen
 * outside of your window bounds, where there is no view to receive it.
 * 
 * @param event The touch screen event being processed.
 * 
 * @return Return true if you have consumed the event, false if you haven't.
 * The default implementation always returns false.
 */
public boolean onTouchEvent(MotionEvent event) {
    if (mWindow.shouldCloseOnTouch(this, event)) {
        finish();
        return true;
    }
    
    return false;
}

從上面的說明可以看出,當觸屏事件沒有被內(nèi)層所有的view處理的時候才會被調(diào)用;當處理你窗體外沒有任何view處理的Touch事件的時候最有用。
從返回值說明可以看出,默認返回值通常為false,所以一般如果事件不被子view消費,事件一般都會被舍棄掉

2.從Activity中傳入外層的ViewGroup中

經(jīng)過了UserActivty后傳入到ViewParent中來,第一個走的肯定還是dispatchTouchEvent,依然,如果手動修改dispathTouchEvent的返回值,本次事件就到此為止。如果使用父類(ViewGroup)的事件分發(fā)機制,那么事件就會首先傳遞到onInterceptToucEvent中來;(這部分里面代碼太多,我想你也沒興趣看;萬一你是個Geek,那你也可以自己去扒一扒源碼,自己閱讀一下,這里就不再詳細介紹了,本文就是為了言簡意賅的說明Touch事件的傳遞機制,所以見諒)

  • 在onInterceptTouchEvent中,就會詢問你“你想不想攔截本次事件?。俊?br> |--"想"(return true),那么事件就會進入自己的onTouchEvent中執(zhí)行
    那么事件就會到了onTouchEvent中,這時系統(tǒng)就會問你:“你想不想處理這次點擊事件???”
    |--"想"(return true)那么本次事件被消費掉了
    |--"不想"(return false)那么他就會認為你里層的子控件都不想接收本次事件,那他直接把本次事件往回傳遞(傳回UserActivty中
    去處理)。需要注意的是,如果本次事 件是DOWN事件,那么本次的MOVE、UP也將不會傳遞到ViewParent中來了,注意是本次哦,僅僅只是指你一次
    按下到抬起這一套動作,還有第二次,第三次,還是要來的。
    |--"你自己說了算,按照你的想法去做吧!"(return super.onTouchEvent(ev);)那就要交給ViewParent的父類去決定了,不過一般
    ViewGruop中都不會去處理事件,即一 般返回false
    |--"不想"(return false),既然你不想攔截,那我就去問問你里面的人想不想處理吧,事件就會向里層傳遞,即下面的ViewChild
    |--"你自己說了算,按照你的想法去做吧!"(return super.onTouchEvent(ev);),系統(tǒng)當然是想有人來消費這個事件了,既然你
    讓我自己決定,那我也想向你里面的子控件問問?。?/li>

3.事件傳遞到了ViewChild中

這里當然是最里層控件了.
dipatchTouchEvent:還是和上面的一樣,還是決定是否分發(fā)事件,系統(tǒng)的邏輯會自動運行到自己onTouchEvent方法中,如果你主動干預(yù),決定是否分發(fā)(手動更改返回值),事件到這里就會終結(jié)
onInterceptTouchEvent:最里層控件沒有這個方法,既然是最里層的控件,自然就不需要詢問你是否需要攔截這個事件了,因為你攔不攔截,事件到這里就算是走到了路的盡頭(之所以稱為路的盡頭,是因為還可以走走回頭路的,哈哈?。┧赃@里沒有啊onInterceptTouchEvent方法
onTouchevent:邏輯和之前的一樣,問你是否消費本次事件,
|--return true消費掉本次事件,事件結(jié)束;
|--return false不消費,本次事件回傳到外一層控件,同樣,如果是一次DOWN事件,本次的MOVE和UP將不會再傳遞到這里;
|--return super.onTouchEvent(event)是否消費本次事件就要看自己控件類型了,我的例子中是TextView類型,就是不消費的;

4.事件回傳

事件回傳,差不多是同一種情況,就是當前控件中的onTouchEvent返回值為false(默認的super.onTouchEvent方法一般也是返回false),可以理解為:
|--return false:事件都交到你手里了,而且你明確說了你不要,那我只能往回傳了;
|--return super.onTouchEvent(event):如果你不告訴我你要不要處理,我只能默認你不處理,也就往上一層傳遞了
當?shù)竭_了最頂層,我的Demo程序中是MainActivity,默認不處理onTouchEvent,所以如果回傳到頂層,事件會調(diào)用Activity中的onTouchEvent
本次分析到這里就算結(jié)束了,感覺有些地方的理解還存在問題,歡迎各位大神指點,先謝過了!
本次使用的圖片資源和源代碼,如需要,請自行下載:
鏈接:http://pan.baidu.com/s/1kTH59sj密碼:1m5n

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容