Android View架構總結(九)KeyEvent事件分發機制

來源:互聯網
上載者:User

標籤:

請尊重分享成果,轉載請註明出處:
http://blog.csdn.net/hejjunlin/article/details/52335094

本篇開始分析按鍵訊息事件分發(PS:本篇文章中源碼均是android 6.0,請知曉)先看下Agenda:

  • ViewRootImpl中的dispatchInputEvent方法
  • View.dispatchKeyEvent方法
  • ViewGroup.dispatchKeyEvent方法
  • Activity.dispatchKeyEvent方法
  • 按鍵訊息事件時序圖
ViewRootImpl中的dispatchInputEvent方法

WMS中接受到訊息後,會調用ViewRootImpl中的dispatchInputEvent方法,
如下:
ViewRootImpl.java -> dispatchInputEvent()

下面看ViewRootHandler的handleMessage方法:
ViewRootImpl$ViewRootHandler.java -> handleMessage()

以上擷取msg中的event,及receiver後,接著調用enqueueInputEvent方法
ViewRootImpl.java -> enqueueInputEvent()

以上方法,由於預設是false,會執行2:
ViewRootImpl.java -> scheduleProcessInputEvents()

以上方法,再給Handler發一條MSG_PROCESS_INPUT_EVENTS(處理的訊息)
ViewRootImpl$ViewRootHandler.java -> handleMessage()

ViewRootImpl.java -> doProcessInputEvents()

上面有個迴圈操作,就是把QueuedInputEvent傳遞到deliverInputEvent方法中,主要的作用,就是把上面來的按鍵訊息放到隊列中去。
ViewRootImpl.java -> deliverInputEvent()


ViewRootImpl提供一個setView方法,是一個public的,會把mView(也就是DecorView),WMS調用這個方法,注意ViewRootImpl並不是一個View,它實際上是一個Handler,它的作用如下:

向DecorView分發收到的使用者發起的event事件,如按鍵,觸屏,軌跡球等事件;(這個是在內部類中實現,下面會說)

與WindowManagerService互動,完成整個Activity的GUI的繪製。

看下setView方法

上面有兩個內部類,ViewPostImeInputStage,
ViewRootImpl.java$ViewPostImeInputStage

在看processKeyEvent之前,先看onProcess方法:
ViewRootImpl$ViewPostImeInputStage.java -> processKeyEvent




ViewRootImpl.java -> handleDispatchWindowAnimationStopped()

上面有些代碼比較長,瞭解下就行,主要是明白processKeyEvent方法:
KeyEvent是InputEvent的子類,而InputEvent是一個事件的基類。
處理接收的事件及分發事件的過程,那麼問題來了?view或者viewGroup是如何收到按鍵訊息派發下來的呢?ViewRootImpl內部類ViewPostImeInputStage中的processKeyEvent()方法中有這麼一段
if (mView.dispatchKeyEvent(event)) {//mView是DecorView(書名),但本質上也是View(乳名)
return FINISH_HANDLED;
}
另外鍵盤訊息派發到view或ViewGroup中,在ViewRootImpl另一個內部類ViewPreImeInputStage中的processKeyEvent()方法中也有這麼一段如下:

View.dispatchKeyEvent方法

可以看到從這開始就把按鍵訊息派發到了view中去,然後看view中的dispatchKeyEvent():

KeyEvent.java -> dispatch()


ViewGroup.dispatchKeyEvent方法

再來看下ViewGroup中的dispatchKeyEvent()

上面代碼總結為:ViewGroup是重寫了View的dispatchKeyEvent,如果有子view時,分發按鍵訊息到子view中去。沒有,直接由父view分發。

Activity.dispatchKeyEvent方法

到這就完了嗎?沒有,Activity中dispatchKeyEvent,這不是個重寫方法:

以上代碼總結為:先讓actionbar優先處理keyEvent,然後通過window處理,處理不了,到window上的DecorView處理。window和decorview的關係,相當於一個是窗戶,一個是粘在窗戶上的紙。所以,decorview可理解為窗戶上的紙。Activity的dispatchKeyEvent,是用於處理KeyEvent相關,子類可以重寫攔截所以的key event訊息在分發到window這一層去的時候,所以我們最好做一些正常的處理流程。
主要過程如下:
1、調用onUserInteraction(),可重載該函數在訊息派發前做一些處理
2、回調Activity包含的Window對象的superDispatchKeyEvent,該函數繼而調用mDecor.superDispatchKveyEent,該函數繼而又調用super.dispatchKeyEvent,DecorView的父類是FrameLayout,而FrameLayout未重載dispatchKeyEvent,因此最終調用ViewGroup的dispatchKeyEvent
3、如果DecorView未消耗訊息,則調用event的dispatch()函數,這裡的第一個參數receiver是Activity對象

寫到這,有一個疑問?就是一個訊息怎麼從window派發到viewRoot中去呢?或者說ViewRoot中的按鍵訊息是從哪來的?
ViewRoot中有一個內部類: W,W是一個Binder子類(static class W extends IWindow.Stub ),用於接收global window manager的各種訊息, 如按鍵訊息, 觸摸訊息等。 ViewRoot有一個W類型的成員mWindow,ViewRoot在構造中建立一個W的instance並賦值給mWindow(mWindow = new W(this);)。 ViewRoot是Handler的子類, W會通過Looper把訊息傳遞給ViewRoot。

按鍵訊息事件時序圖

一張圖,總結上面的流程:

第一時間獲得部落格更新提醒,以及更多android乾貨,源碼分析,歡迎關注我的公眾號,掃一掃下方二維碼或者長按識別二維碼,即可關注。

如果你覺得好,隨手點贊,也是對筆者的肯定,也可以分享此公眾號給你更多的人,原創不易

Android View架構總結(九)KeyEvent事件分發機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.